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

Creating a Photo Gallery, Part #4

March 27, 2007

[PDF VERSION AVAILABLE HERE]

The past few weeks, since the last part #3, has seen quite a bit of internal rewriting in the Photo Gallery application.  This part isn’t going to include all of those changes, but perhaps spark some ideas in how you might change your application.

I’m going to discuss:

·         Moving to Object Oriented…

·         How to save multiple file types, such as PDFs, Word DOCs, and Excel XLSs.

 

Both of these topics go hand in hand and, in how I wrote it, is asynchronous.  We are moving away from a “photo” gallery into a “storage repository” of information.  We now have two types of objects—photos and non-photos that have similar properties, but some different methods.  This leads very well for a bit of information on inheritance and objects.  This will NOT be a full walkthrough of inheritance and will be mostly the ‘quick and dirty’ methodology, but provides the basic concept—everything else has already been written and can be Google’d quite quickly.

 

COMMENT: There isn’t an online version of this post yet; BlogJet keeps doing some CRAZY things, but I’ll get it posted up here soon.  For now, the PDF is available at the top of the post.

 

UPDATE (17 April 2007) : Here’s the body of the PDF for your reading pleasure.  For the photos, please use the PDF.  I’ll fix this for part #5 (I hope!).

 

Tags: , , ,

 

Creating a Photo Gallery, Part #4

The past few weeks, since the last part #3, has seen quite a bit of internal rewriting in the Photo Gallery application.  This part isn’t going to include all of those changes, but perhaps spark some ideas in how you might change your application.

I’m going to discuss:

·         Moving to Object Oriented…

·         How to save multiple file types, such as PDFs, Word DOCs, and Excel XLSs.

Both of these topics go hand in hand and, in how I wrote it, is asynchronous.  We are moving away from a “photo” gallery into a “storage repository” of information.  We now have two types of objects—photos and non-photos that have similar properties, but some different methods.  This leads very well for a bit of information on inheritance and objects.  This will NOT be a full walkthrough of inheritance and will be mostly the ‘quick and dirty’ methodology, but provides the basic concept—everything else has already been written and can be Google’d quite quickly.

“Objectizing” Our Photo Gallery

After realizing the power of the Photo Gallery, I wanted to remove myself from box.net and other online repositories that I typically tossed documents out to… for even uses such as this document, which will be linked to my blog, but requires a web location.  The first step was, however, to break our logic into two separate object types—photos (things that required a graphical thumbnail) and non-photos (things that we’ll use standardized thumbnail icons).

What has changed since Part #3?

·         Renamed this the ‘WebStorage’ project—to better match what it’s doing now.

·         I implemented the Enterprise Library’s Data module (Jan 2006 release, not confident enough for the 2007 CTP) for storage lookup—removing the platform dependency. 

·         Broke the logic contained in code-behind pages into an additional class file containing four files: StoredObject, Photo, File, and Gallery.  Photo and File inherit from the StoredObject.

Our StoredObject, File, and Photo appear as below.  The properties match to corresponding protected variables of the same type.

For our StoredObject object, it is the backbone of the site… responsible for both the properties of each object as well as loading (displaying), moving (between galleries), saving (uploading to a gallery), and deleting (umm, deleting) of objects.  With inheritance, we can just code the deltas (differences).  As you see above, Photos and Files override Load (since they are streamed out differently), but reference similar properties.

From StoredObject.cs:

public virtual string Load()

{

  return null;

}

From File.cs, where we’re overriding with:

public override string Load()

{

  LoadObject();

  HttpContext.Current.Response.ContentType = _contentType;

  HttpContext.Current.Response.AddHeader(“content-disposition”, “inline; filename=” + _fileName);

  HttpContext.Current.Response.BinaryWrite(_objectBytes);

  HttpContext.Current.Response.End();

   

  return SuccessMessage();

}

 And with Photo.cs, we’re handing it a bit different by returning:

public override string Load()

{

  LoadObject();

   

using (MemoryStream stream = new MemoryStream(_objectBytes))

   {

        _outputImage = Image.FromStream(stream);

  }

  _fullSizeImage = new Bitmap(_outputImage);

        HttpContext.Current.Response.ContentType = _contentType;

        _fullSizeImage.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Jpeg);

  HttpContext.Current.Response.End();

   

  return SuccessMessage();

}

       

We’ll touch on the Gallery object and it’s refactoring in the next tutorial. 

The last modification was to our trusty ValidContentTypes object.  Now, we need to actually request if we want File(s) or Photo(s).

From here, we can call this object in our Load, Save, and Delete (or any method that may require a bit of handling logic) and check for the appropriate content type.

For example, in our Save method:

internal static List<String> ValidContentTypes(string objectType)

        {

            List<String> validContentTypes = new List<String>();

            switch (objectType)

            {

                case “Photo”:

                    validContentTypes.Clear();

                    validContentTypes.Add(“image/gif”);

                    validContentTypes.Add(“image/jpeg”);

                    validContentTypes.Add(“image/pjpeg”);

                    validContentTypes.Add(“image/png”);

                    return validContentTypes;

                case “File”:

                    validContentTypes.Clear();

                    validContentTypes.Add(“application/pdf”);

                    return validContentTypes;

                default:

                    return validContentTypes;

            }

        }

public string Save()

{

  List<String> validContentTypes = ValidContentTypes(_objectType);

   if (validContentTypes.Exists(delegate(string t) { return _contentType == t; }))

   {

        SaveObject();

         return SuccessMessage();

  }

   else

   {

        return ErrorMessage();

  }

}

  

If our object’s _contentType exists in the dictionary list of valid content types based on the _objectType, then proceed. 

Managing Multiple File (and Content) Types

Overall, the trick to multiple file and content types was handled by our refactoring process—the ability to create separate objects for each object that requires a different handling method.  The rest is handled by a bit of tweaking to our Handler:

public void ProcessRequest(HttpContext context)

    {

        int id = Convert.ToInt32(context.Request.QueryString[“id”]);

        string objectType = context.Request.QueryString[“type”];

        bool thumbnail = Convert.ToBoolean(context.Request.QueryString[“tb”]);

        switch (objectType)

        {

            case “Photo”:

                if (thumbnail)

                {

                    ReturnPhotoThumbnail(id);

                }

                else

                {

                    ReturnPhoto(id);

                }

                break;

            case “File”:

                if (thumbnail)

                {

                    ReturnFileThumbnail(id);

                }

                else

                {

                    ReturnFile(id);

                }

                break;

            default:

                break;

        }

    }

That leaves us with the return methods:

private static void ReturnFile(int id)

    {

        File fi = new File();

        fi.Id = id;

        fi.Load();

    }

    private static void ReturnFileThumbnail(int id)

    {

        File fi = new File();

        fi.Id = id;

        fi.LoadThumbnail();

    }

  

The objects take care of the rest—no “logic” in the handler, only inherited from our StoredObject and File (or Photo).

So, we’re familiar with how the Photos are processed from the prior three parts, the logic didn’t change—it was only relocated.  File handling; however, is a new beast to deal with.  Thankfully, they are, in my opinion, MUCH easier.  Primarily, there isn’t anything to create a thumbnail of based on specific calculations; but what do we do about thumbnails?   Easy!  Use your own icons! 

Displaying Thumbnails Based on Content Type

While I’m sure there’s a MUCH easier way to do this (or more proper), this will provide a start.  Remember that we have a LoadThumbnail method we can override for the StoredObject?  That’s what we’re going to do, except this time, we’ll use a file on our local server.  For this, we’ll use a simple PDF icon and a document icon for everything else.

public override string LoadThumbnail()

{

  string fileIcon;

   LoadObject(false);

   switch (_contentType)

   {

        case “application/pdf”:

                    fileIcon = “pdf.png”;

                break;

        case “application/doc”:

                    fileIcon = “doc.png”;

                break;

        default:

                    fileIcon = “empty.png”;

              break;

  }

   HttpContext.Current.Response.ContentType = “image/png”;

   FileStream fileStream = new FileStream(HttpContext.Current.Server.MapPath (“images/filetypes/”) + fileIcon,FileMode.Open, FileAccess.Read, FileShare.Read);

   long fileSize = fileStream.Length;

   byte[] fileBuffer = new byte[(int)fileSize];

   fileStream.Read(fileBuffer, 0, (int)fileSize);

   fileStream.Close();

   HttpContext.Current.Response.BinaryWrite(fileBuffer);

   HttpContext.Current.Response.End();

   return SuccessMessage();

}

 That method simply looks at the content type of the File we’re returning, either a PDF or a DOC (which is all we allow right now), and returns an icon from the file system using a FileStream object.  Once you have the icon off of the file system and into a byte array, you simply stream it to the web browser as you would the PDF itself:

public override string Load()

{

  LoadObject();

   HttpContext.Current.Response.ContentType = _contentType;

   HttpContext.Current.Response.AddHeader(“content-disposition”, “inline; filename=” + _fileName);

   HttpContext.Current.Response.BinaryWrite(_objectBytes);

   HttpContext.Current.Response.End();

   return SuccessMessage();

}

Unlike our Photos, that uses the Bitmap.Save method to dump the image to an OutputStream; files use the Response.BinaryWrite method.

Modifying The DataList

The final step is to modify our DataList to recognize the new query string variables.  We now have an objectId and ObjectType to pass to our handler.

<a href=”<%# String.Format(“WebStorageHandler.ashx?id={0}&tb=false&type={1}”, Eval(“Id”), Eval(“ObjectType”)) %>target=”_blank”>

  <img alt=”” src=”<%# String.Format(“WebStorageHandler.ashx?id={0}&tb=true&type={1}”, Eval(“Id”), Eval(“ObjectType”)) %>style=”border-top-style: none; border-right-style: none; border-left-style: none; border-bottom-style: none” />

</a>

Notice our hyperlink (<a href …>) has a tb (thumbnail) set equal to ‘false’ while our image (<img … >) is set to true.  We simply added an additional query string parameter in for the type, which is read by the handler.

The End Product

With all of that done, browsing the gallery gives us a demonstration of our hard work.  Photos look the same:

But our recently uploaded files give us their details and a helpful icon as their thumbnail:

In the next part, we’re going to add a bit more functionality to our storage library:

·         Creating and maintaining galleries,

·         Maintaining photos,

·         And a bit of fun with dynamic resizing and watermarking photos.

 

Categories: .net 2.0, c#
  1. Horsted
    March 28, 2007 at 6:28 pm

    Hi there,

    Your Photo-gallery very interresting. Is it there anywhere I can download the source-code? Thanks in advance!

  2. April 13, 2007 at 10:33 am

    Horsted –

    The source isn’t all ‘put together’ yet; if you’re interested in a particular code part, let me know and I can email it to you. There’s one section left and the full source will be attached with that.

    -dl

  3. Horsted
    April 18, 2007 at 3:19 am

    Hi again,

    I’ll just wait for the last section – really looking forward to it. Thanks alot for sharing!

  4. October 16, 2008 at 7:59 am

    Hi Horsted,
    I find your tutorials on the photo gallery very interesting. Is there a way I can download the version 1 full source code?

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: