Home > .net 2.0, c# > Creating a Photo Gallery, Part #1

Creating a Photo Gallery, Part #1

January 5, 2007

So, as I have previously mentioned, finding a photo gallery that suits my needs has been… quite troublesome.  Quite frankly, and as a preface to this and a few following blog posts, I will most likely go with Yahoo’s Flickr.  The features and price match what I’m looking for–and reinventing the wheel is rarely productive.

However, figuring out HOW is another story.

To begin, there is somewhat of a progression to the entire tale.  I probably refractored and redesigned more code in the past two days than should be necessary for a “photo album,” but the learning and trying out new techniques (especially IHttpHandlers and GDI) has been a pretty interesting experience.

Some tidbits included over the series will be:

  • Part #1: Writing to and reading from the hard drive for Images (using the FileUpload.SaveAs web control), auto generation of thumbnails using Image.GetThumbnailImage,
  • Part #2: Using IHttpHandler and custom Http Handlers for output, writing to and reading from SQL Server 2005/SQL Express for Images (using SqlDbType.Image),
  • Part #3: Displaying it all out, through both the handler and a GridView.

Note, nothing is perfect… this has been, if nothing else, a good way to kick myself back into programming gear after a two week break of holidaying… also, most of these show examples of using controls or techniques—I’ve left out several key aspects—such as exception control—for simplicity reasons.

Saving to and Reading from the Hard Drive

The first iteration of the application relied on two directories–galleries and thumbnails–and saved the images to the hard drive.  This was quite elementary using the new ASP.NET 2.0 FileUpload control.

First off, our upload form required the FileUpload control and a button to execute the upload.

https://tiredblogger.files.wordpress.com/2007/01/windowslivewritercreatingaphotogallerypart1-b243clip-image002.jpg

Upload the File

In our code-behind, we are ready to capture the Image. By using the FileUpload control’s browse functionality to select a file, we are reading to click our ‘FileSystem Upload’ button.

protected void btnUpload_Click(object sender, EventArgs e) {

string originalFileName = “”;
string uploadStatus = “”;
string thumbnailFileName = “”;
string thumbStatus = “”;

if (uploader.HasFile) {

try {

originalFileName = PhotoStorage.UploadPhoto(uploader, out uploadStatus);

lblUploadStatus.Text = uploadStatus;
}

catch {  }

}

We’ll get to the PhotoStorage class here in a bit, I’ve separated out the logic in the application, but for now, let’s focus on what we’re using the ‘uploader’ for.

To begin, the uploader object has a Boolean property of HasFile—a quick verification that the user has placed a file into the entry box and the application can capture that file.

Next, after we have verified that (.HasFile == true), we pass the entire uploader object to PhotoStorage.UploadPhoto method. We also have an outbound string in our signature that returns the status. Let’s look at that method.

Prior to our code, the actual class contains four variables—pulling in the configuration settings from our web.config and making them available to the class. This just saves a bit of excess typing down the road.

// The relative paths of ~\directory
public static string galleryPath = ConfigurationManager.AppSettings[”galleryPath”].ToString();
public static string tbPath = ConfigurationManager.AppSettings[”tbPath”].ToString();

// The Server paths of driveletter:\\directory\\directory\\directory
public static string contextGalleryPath = HttpContext.Current.Server.MapPath(galleryPath);
public static string contextTbPath = HttpContext.Current.Server.MapPath(tbPath);

public static string UploadPhoto(FileUpload uploader, out string uploadStatus) {

string fullUploadName = Path.Combine(contextGalleryPath, uploader.FileName);

// Does the photo already exist in the galleries?
if (File.Exists(fullUploadName)) {

// Sorry, file exists!

uploadStatus = “Your image (” + uploader.FileName + “) already existed in the specified gallery.”;

return uploader.FileName;

}
else {
try {

uploader.SaveAs(fullUploadName);

uploadStatus = “Your image (” + uploader.FileName + “) uploaded successfully “;

return uploader.FileName;

}

catch (Exception ex) {

uploadStatus = “Your image (” + uploader.FileName + “) failed to upload.” + Environment.NewLine + “Error: ” + ex.Message;

return null; }

}
}

FileUpload.SaveAs

requires that your ASP.NET worker process (or in VS2005) have write access to the location you are trying to save to. The other caveat, as you see from the variables, is that it requires the actual server path, not a relative path. http://www.server.com/mydirectory/ will not work, it must be d:\inetpub\wwwroot\mydirectory\ or the equivalent for your site.

If successful, the file has uploaded and returned the output “uploadStatus” message to the user. This is assigned to the lblUploadStatus.Text value.

Generate the Thumbnail

Our next step is to generate a thumbnail in our thumbnails directory. The btnUpload_Click method that we called earlier has another action after uploading the file: generate the thumbnail.

try {

thumbnailFileName = PhotoStorage.CreateThumbnail(originalFileName, out thumbStatus);

lblThumbStatus.Text = thumbStatus;
}

catch { }

Here, we’re again calling our PhotoStorage class and the CreateThumbnail method, passing it the originalFileName variable (from our UploadPhoto method) and asking for another output Status message.

public static string CreateThumbnail(string originalFileName, out string thumbStatus) {

string thumbnailFileName = “”;
int thumbHeight = 0;
int thumbWidth = 0;

try {

// Import the original image into an Image object.

System.Drawing.Image originalImage =
new Bitmap(Path.Combine(contextGalleryPath, originalFileName));

// Set our variables.
thumbnailFileName = “_tb_” + originalFileName;

// First, let’s not create a thumbnail if one already exists.
if (File.Exists(Path.Combine(contextTbPath, thumbnailFileName))) {

// Already exists; skip!

thumbStatus = “The thumbnail (” + thumbnailFileName +
“) already existed in the gallery.”;

return thumbnailFileName;

}
else {

// To keep somewhat standardized, but not ’squish’ portrait pictures, set the thumbnail
// width and height based on the orientation of the picture.

if (originalImage.Height > originalImage.Width) // Portrait picture
{

thumbHeight = 150;

thumbWidth = 100;
}

else if (originalImage.Height < originalImage.Width) // Landscape picture
{

thumbHeight = 100;

thumbWidth = 150;
}

else if (originalImage.Height == originalImage.Width) // Square picture
{

thumbWidth = 150;

thumbHeight = 150;
}

// Generate the thumbnail image.

System.Drawing.Image thumbnailImage =
  originalImage.GetThumbnailImage(thumbWidth, thumbHeight, null, new IntPtr());

// Save this image to the thumbnails directory using
// the _tb_FILENAME and using JPEG compression.

thumbnailImage.Save(Path.Combine(contextTbPath, thumbnailFileName), ImageFormat.Jpeg);

thumbStatus = “The thumbnail (” + thumbnailFileName + “) created successfully.”;

return thumbnailFileName;

}
}

catch (Exception ex) {

thumbStatus = “The thumbnail (” + thumbnailFileName + “) could not be created.” +
Environment.NewLine +
“Error: ” + ex.Message;

return null;

}
}

The logic here is a bit simplistic, simply setting the thumbnail’s width and height depending on whether or not it is taller or wider—further iterations will actually scale based on percentages.

Here, you see the Image.GetThumbnailImage method. This method takes four inputs: the width, the height, an error call (which I left null, normally you would call the GetThumbnailImageAbort), and a pointer, which is set to zero.  I would like to point out that many developers dislike the GetThumbnailImage method, but I have yet to find a real good explanation as to why (aka: if you have info, post a comment!).

Displaying the Thumbnail to the User

Finally, we want to use our placeholder control, phImagePlaceholder, and fill it with the recently uploaded thumbnail. We accomplish this by calling the DisplayThumbnail method in our PhotoStorage class.

try {

phImagePlaceholder.Controls.Add(PhotoStorage.DisplayThumbnail(originalFileName));
}
catch { }

The DisplayThumbnail generates, what I feel, is the most simplistic control, an ASP.NET Hyperlink control, assigns it the ImageUrl, NavigateUrl, and Target, and returns it back to the placeholder.

public static Control DisplayThumbnail(string originalFileName) {

try {

HyperLink hl = new HyperLink();

hl.ImageUrl = tbPath + “_tb_” + originalFileName;

hl.NavigateUrl = galleryPath + originalFileName;

hl.Target = “_blank”;

return hl;
}

catch (Exception ex) {

return null;
}
}

Test it out!

So, let’s try it out! Build and run the project. Browsing to and uploading a file should give you a result that looks like:

https://tiredblogger.files.wordpress.com/2007/01/windowslivewritercreatingaphotogallerypart1-b243clip-image004.jpg

You’ve successfully used the FileUpload control, uploaded a file from the web to your local hard drive, used the Image.GetThumbnailImage to create and save a thumbnail to the hard drive, and returned the results to the user.

Coming in Part #2

In Part #2, we’re going to take the lessons learned here and turn it around and move to a more modern approach—storing the images in a database and using IHttpHandlers rather than the PhotoStorage class to handle our image creation and manipulation.

I’ve attached the primary code file, PhotoStorage.cs as PhotoStorage.pdf (why can’t I upload .txt to WordPress?!) and PhotoGalleryPart1.pdf (a PDF of this guide) to this blog post for your reference.

Categories: .net 2.0, c#
%d bloggers like this: