Click here to Skip to main content
Click here to Skip to main content

Using ImageMagick to Create Previews and Thumbnails from Uploaded Images

, 2 Sep 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
This ASP.NET Web Application demonstrates the use of ImageMagick to create thumbnails and larger preview images, both from an uploaded image file.

IM_WebSample.png

Introduction

This article and the accompanying ASP.NET Web Application demonstrate the use of ImageMagick, a well-known open-source application from ImageMagick Studio LLC. The application creates a small thumbnail image and a larger preview image, both from a single JPEG or TIFF image, uploaded by the user through a web-browser. The application was written in C# using Microsoft Visual Studio 2008 and Developer Express' CodeRush. Developer Express' Refactor! Pro was used to optimize and refactor the source code.

Background

Working in the graphic arts industry, much of the development I am involved with deals with the creation, processing, storage, and distribution of images and visually rich documents. One such recent project was the creation of a web-to-print solution for the Fine Art Reproduction division of our company, Lazer Incorporated. Preview the site at Lazer Incorporated Fine Art Gallery. The fine arts web-to-print web solution consists of three primary user interfaces, as follows:

  1. Public art gallery to display the works of artists who use our services
  2. Private and secure ordering system for artists to order fine art prints and other services
  3. Customer service interface to administer the artists, artwork, thumbnail/previews, and orders.

The fine arts application is an ASP.NET 2.0 Web Application, written in C# 2.0 using Microsoft Visual Studio 2005. The solution uses SQL Server 2005 for storage of artist and artwork data. The solution integrates XML Flash Slideshow v3, an Adobe Dreamweaver Flash-based extension from dwusers.com, to display the artist's portfolio. In addition, the solution automatically creates thumbnails and larger preview images of the artwork using ImageMagick. ImageMagick is a free application from ImageMagick Studio LLC. ImageMagick is available for multiple Operating Systems and programming environments.

Using the Code

The Application

The application calls ImageMagick v6.4.5 from the command-line to create thumbnails and previews from a single uploaded image file. It duplicates the approximate functionality of the aforementioned fine art solution's thumbnail/preview creation routine. The application is written in Visual Studio 2008 using C# 3.0. This simple application contains a single Web Form and an associated class file. The application's workflow is as follows:

  1. User uploads a TIFF or JPEG image, less than 5 Mbs in size, through the web browser.
  2. Application verifies the image has been successfully uploaded, and is within the specs above.
  3. Application calls ImageMagick from the command-line to return information about the uploaded image (optional).
  4. Application calls ImageMagick to create a small thumbnail image from the uploaded image, no bigger than 100 pixels in height.
  5. Application calls ImageMagick to create a larger-sized preview image, no bigger than 450 pixels in width or height.
  6. Application deletes the original uploaded file from the server.
  7. Application returns a detailed status report of all the actions to the user.

Preparing to Install the Application

Before you compile and run the source files provided, you must complete two simple tasks. First, download and install ImageMagick. As of the date of this article, v6.5.2-1 is the most current. Since the instructions to install ImageMagick are so well documented at http://www.imagemagick.org/script/binary-releases.php#windows, I won't be redundant, herein.

Secondly, install the folder-set I have provided as part of the source code. Inside the ImageMagick parent folder of the set, there are four folders. They will hold uploaded images, thumbnails, previews, and an ICC color profile. The profile ensures optimal color accuracy during image conversion and display of images in the web-browser. The source code assumes you will install the folder-set at the root-level of your C: drive (c:\imagemagick). You can easily change this property in the source code, if necessary.

After downloading the folders, create a virtual directory within Internet Information Server (IIS), with the local path pointed to the 'imagemagick' folder (see screen capture below). This step is necessary so the application can display the preview and thumbnail in the web-browser after they are created.

IM_IISVD.png

Lastly, you must give the ASP.NET user account read and write access to the folder-set (see screen capture below). The Web Application, and subsequently ImageMagick, will need these privileges to create the new images in the appropriate folders, read the images back into the web-browser, and delete the original uploaded image.

IM_Share.png

Installing the Application

Now, you can download and install the source files and compile the web application. To do so:

  1. Create a new C# ASP.NET Web Application in VS 2008 called 'IMPreviewDemo'.
  2. Replace the Default.aspx Web Form with the Default.aspx form provided.
  3. Install the Global.aspx, ImageMaker.cs, Result.cs files in the root directory of the IMPreviewDemo application.
  4. Optionally, open your existing Web.config file and add a <httpRuntime/> tag to the <system.web> section (see screen capture below). This will allow you to also adjust the maximum allowable uploaded image size, and also importantly, set a time limit for uploads to complete.

IM_WebConfig.png

The Code

The Default.aspx Web Form contains the VerifyUpload() method. When the Process button is clicked, VerifyUpload() checks that the file has successfully been uploaded, and checks that the file is either a JPEG or TIFF file. VerifyUpload() returns a value indicating whether or not the tests were passed. Only then is an instance of the ImageMaker class created, and a call placed to the ProcessImage(string uploadedFile, int detailLevel) method, part of the ImageMaker class.

using System;

namespace IMPreviewDemo
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if(Request.QueryString["error"] == "filesize")
            {
                Message.CssClass = "textred";
                Message.Text = "File was to large to upload. Must be < 5 Mb.";
            }
        }
        protected void Process_Click(object sender, EventArgs e)
        {
            ImagePanel.Visible = false;
            if(VerifyUpload() == Result.Success)
            {
                CreateImages();
            }
        }
        protected Result VerifyUpload()
        {
            if(ImageUpload.HasFile)
            {
                string fileExtension = System.IO.Path
                    .GetExtension(ImageUpload.FileName).ToLower();
                string[] allowedExtensions =
                    new string[] { ".jpeg", ".jpg", ".tif", ".tiff" };
                foreach(string allowedExtension in allowedExtensions)
                    if(fileExtension == allowedExtension)
                        return Result.Success;
            }
            Message.CssClass = "textred";
            Message.Text = 
                "Cannot accept this image type. Must be JPEG or TIFF.";
            ImagePanel.Visible = false;
            return Result.Failure;
        }
        private void CreateImages()
        {
            ImageMaker PreviewMaker = new ImageMaker();
            string uploadedFile = String.Format("{0}{1}",
                ImageMaker.PathUploadedFiles,
                ImageUpload.FileName.Replace(" ", "_"));
            ImageUpload.PostedFile.SaveAs(uploadedFile);
            int detailLevel = Convert.ToInt16(DetailLevel.SelectedValue);
            Message.CssClass = "";
            Message.Text = PreviewMaker.ProcessImage(uploadedFile, detailLevel)
                .Replace("\n", "<br />");
            Thumbnail.ImageUrl = PreviewMaker.UrlThumbnail.ToString();
            Preview.ImageUrl = PreviewMaker.UrlPreview.ToString();
            ImagePanel.Visible = true;
        }
    }
}

The latest version of this application, starting 1.1, uses the Global.aspx file to check uploaded file size. I found this technique on Vikram Lakhotia's Blog. The Application_BeginRequest event checks the uploaded file size. If the file is bigger than the limit I have set, 5 Mb (measured in bytes), an error sent back to the Default.aspx page.

Reviewing the ImageMaker class, you will notice that all file paths are stored in a series of properties and fields at the top of the class. You can modify these to suit your own local file environment. The ImageMaker class also has two fields that identify the path to the ImageMagick application you installed. Again, adjust the fields to match your own environment.

The ImageMaker class has two primary methods. The ProcessImage(string uploadedFile, int detailLevel) method formats the file arguments to be send to the ImageMagick application through the command-line. This method also concatenates and formats the status information returned to the user.

The second method, CallImageMagick(string fileArgs), uses the argument passed to it by ProcessImage(string uploadedFile, int detailLevel) to direct the ImageMagic application from the command-line. Depending on the argument, CallImageMagick(string fileArgs) may or may not return a response string. ImageMagick is called by instantiating the System.Diagnostics.Process class. This class is able to start and stop local system processes.

In the source code, the file arguments passed to ImageMagick are specific to our workflow. We convert the uploaded image to an 8-bit RGB file, scale it down, sharpen it, assign a color profile, and finally save it as a compressed JPEG for display in a web-browser. You can change any of the ImageMagick arguments to fit your needs, along with the file size limitations and file types used in this demo. Refer to the ImageMagick website for a complete list of all ImageMagick's tools and options (arguments).

using System;
using System.Diagnostics;
using System.IO;
using System.Text;

namespace IMPreviewDemo
{
    public class ImageMaker
    {
        //Location of the ImageMagick applications
        private const string pathImageMagick =
            @"C:\Program Files\ImageMagick-6.4.5-Q16\";
        private const string appImageMagick = "MagickCMD.exe";

        //Names for images created by ImageMagick
        private string ticksID;
        private string previewName;
        private string thumbnailName;

        //Paths to all the file folders
        private const string pathRoot = @"C:\imagemagick";
        private const string pathPreviews = pathRoot + @"\previews\";
        private const string pathThumbnails = pathRoot + @"\thumbnails\";
        private const string pathColorProfile = pathRoot + @"\profiles\";

        private const string colorProfile =
            "sRGB_IEC61966-2-1_black_scaled.icc";

        public static string PathUploadedFiles
        { get { return String.Format(@"{0}\uploads\", pathRoot); } }

        //URLs of images created by ImageMagick 
        //(assumes imagemagick folder a virtual directory in IIS)
        public Uri UrlThumbnail { get; private set; }
        public Uri UrlPreview { get; private set; }

        StringBuilder sbResults = new StringBuilder();

        public string ProcessImage(string uploadedFile, int detailLevel)
        {
            try
            {
                ticksID = DateTime.Now.Ticks.ToString();
                sbResults.AppendLine(String.Format("Start time: {0}\n",
                    DateTime.Now.ToLongTimeString()));
                if(detailLevel == 1) { GetFileInfo(uploadedFile); }
                CreateThumbnailImage(uploadedFile);
                CreatePreviewImage(uploadedFile);
                File.Delete(uploadedFile);
                sbResults.AppendLine(String.Format("Uploaded file deleted: {0}\n",
                    uploadedFile));
                sbResults.AppendLine(String.Format("Stop time: {0}\n",
                    DateTime.Now.ToLongTimeString()));
                return sbResults.ToString();
            }
            catch(Exception ex)
            {
                return ex.Message;
            }
        }
        private void GetFileInfo(string uploadedFile)
        {
            string fileArgs = String.Format("identify -verbose {0}", uploadedFile);
            sbResults.AppendLine(String.Format("Uploaded file arguments: {0}\n",
                fileArgs));
            sbResults.AppendLine(String.Format("Uploaded file info: {0}\n",
                CallImageMagick(fileArgs)));
        }
        private void CreatePreviewImage(string uploadedFile)
        {
            previewName = String.Format("preview_{0}.jpg", ticksID);
            UrlPreview =
                new Uri(String.Format(@"http://localhost/imagemagick/previews/{0}",
                previewName));
            StringBuilder sbFileArgs = new StringBuilder()
                .Append(String.Format("convert {0}", uploadedFile))
                .Append(@" -intent relative")
                .Append(String.Format(@" -profile {0}{1}",
                    pathColorProfile, colorProfile))
                .Append(@" -filter Sinc -resize 450x450>")
                .Append(@" -unsharp .5x.5+.5+0")
                .Append(@" -depth 8")
                .Append(@" -strip")
                .Append(String.Format(@" -profile {0}{1}",
                    pathColorProfile, colorProfile))
                .Append(@" -quality 80 ")
                .Append(pathPreviews + previewName);
            string fileArgs = sbFileArgs.ToString();
            sbResults.AppendLine(String.Format("Thumbnail file arguments: {0}\n",
                fileArgs));
            sbResults.AppendLine(String.Format("Thumbnail created: {0}\n",
                CallImageMagick(fileArgs)));
        }
        private void CreateThumbnailImage(string uploadedFile)
        {
            thumbnailName = String.Format("thumbnail_{0}.jpg", ticksID);
            UrlThumbnail =
                new Uri(String.Format(@"http://localhost/imagemagick/thumbnails/{0}",
                thumbnailName));
            StringBuilder sbFileArgs = new StringBuilder()
                .Append(String.Format("convert {0}", uploadedFile))
                .Append(@" -intent relative")
                .Append(String.Format(@" -profile {0}{1}",
                    pathColorProfile, colorProfile))
                .Append(@" -filter Sinc -resize x100>")
                .Append(@" -unsharp .5x.5+.5+0")
                .Append(@" -depth 8")
                .Append(@" -strip")
                .Append(String.Format(@" -profile {0}{1}",
                    pathColorProfile, colorProfile))
                .Append(@" -quality 60 ")
                .Append(pathThumbnails + thumbnailName);
            string fileArgs = sbFileArgs.ToString();
            sbResults.AppendLine(String.Format("Preview file arguments: {0}\n",
                fileArgs));
            sbResults.AppendLine(String.Format("Preview created: {0}\n",
                CallImageMagick(fileArgs)));
        }
        private static string CallImageMagick(string fileArgs)
        {
            ProcessStartInfo startInfo = new ProcessStartInfo
            {
                Arguments = fileArgs,
                WorkingDirectory = pathImageMagick,
                FileName = appImageMagick,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true
            };
            using(Process exeProcess = Process.Start(startInfo))
            {
                string IMResponse = exeProcess.StandardOutput.ReadToEnd();
                exeProcess.WaitForExit();
                exeProcess.Close();
                return !String.IsNullOrEmpty(IMResponse) ? IMResponse : "True";
            }
        }
    }
}

Conclusion

ImageMagick is a powerful image creation and image-processing engine, capable of the most complex tasks. It is similar to Adobe Photoshop without the GUI in many respects. In addition to the command-line, ImageMagick can be accessed programmatically through its API. There are options available to Windows programmers using COM+ and .NET. You can read more at http://imagemagick.net/script/api.php.

History

  • July 2, 2009 - Version 1.0
    • Initial version
  • August 30, 2009 - Version 1.1
    • Refactored and optimized all code
    • Fixed image refresh bug (see feedback from jessy_j10)
    • Uploaded file size is now checked in the Global.asax file
    • Added option to return either basic or details feedback on processes

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gary Stafford
Software Developer (Senior) Paychex
United States United States
I am a senior software developer, architect, and project manager, specializing in .NET, JavaScript, Java, and database development, and build automation. I am currently a Lead Developer (.NET) / Developer IV for Paychex Enterprise Business Solutions. Paychex (PAYX) provides payroll, human resources, and benefits outsourcing and web-based solutions to business.
 
Prior to Paychex, I served as Lead Software Engineer, Operations Manager, and Technical Product Manager at Bio-Optronics. Bio-Optronics develops, deploys and operates information technology solutions to help healthcare professionals manage and optimize workflow to enhance quality, productivity, and patient and staff satisfaction and safety. Previously, I held positions of President, COO, Chief Technology Officer (CTO), and SVP of Technology for Lazer Incorporated. Lazer is a successful, digital imaging and Internet-based content management services provider.
Follow on   Twitter

Comments and Discussions

 
QuestionCould not load type 'IMPreviewDemo.Global'. [modified] PinmemberMember 1115157527-Oct-14 21:44 
QuestionCannot get this working on win 2003 server IIS 6.0 Pinmemberdtrainer6-Oct-09 5:53 
GeneralMy vote of 1 PinmemberDustinBLair@msn.com17-Sep-09 8:03 
GeneralRe: My vote of 1 PinmemberGary Stafford29-Mar-10 3:59 
GeneralProblem in loading the second image through File upload Pinmemberjessy_j1013-Aug-09 10:22 
GeneralRe: Problem in loading the second image through File upload PinmemberGary Stafford31-Aug-09 3:40 
GeneralRe: Problem in loading the second image through File upload Pinmemberjessy_j108-Sep-09 9:19 
GeneralImage Drag Drop and Swap Pinmemberjessy_j103-Aug-09 11:45 
GeneralImageMagik SQL Server PinmemberBoriska6431-Jul-09 4:27 
GeneralRe: ImageMagik SQL Server PinmemberGary Stafford1-Aug-09 17:32 
GeneralVery good Post but had some problems. Pinmemberjessy_j1030-Jul-09 19:04 
GeneralRe: Very good Post but had some problems. PinmemberGary Stafford1-Aug-09 17:45 
GeneralRe: Very good Post but had some problems. Pinmemberjessy_j103-Aug-09 5:33 
GeneralRe: Very good Post but had some problems. Pinmemberjessy_j103-Aug-09 11:13 
GeneralRe: Very good Post but had some problems. PinmemberGary Stafford31-Aug-09 3:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 2 Sep 2009
Article Copyright 2009 by Gary Stafford
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid