Reading PSD files with c#

Just about every image viewing application these days has support for Photoshop .psd files, so when I searched for code to read such files in c#, I was surprised that there isn’t a “standard” way of doing so.

The code described here was not written by myself. I did add a little to make the code easier for me to use, and will explain my changes further on.

The most reliable c# code I have found for this purpose was written by a Mr Frank Blumenberg. I’ve found various versions online, but they are all clearly copies of his code, whether credit is given to him or not.

I was interested only in the actual classes used, but if you want his latest code, which is a Paint.Net plugin, obviously especially useful if you use Paint.Net, then ignore the rest of this article, and just get his code.

My code is based on what I found on this page on StackOverflow. The very first comment to the question contains a link to an SVN repository which contains the code I used. It’s from an open source screenshot application.

But let’s take a step back and think about how one would use a PSD file parser in c#. There are only two scenarios, in my limited imagination. (And considering that I am not interested in writing to them, only reading them.)

  • To display the composite image. (If the file was saved with a composite image.)
  • To iterate the layers, build a collection of images, and do something with them. i.e. present the user with the option of exporting them to png or something to that affect.

Since I am lazy, I’m only really interested in the first option, and thus the optimizations I’ve made to the code are simply to allow quickly and easily loading the composite image. (Also I’m tired and writing this as well as sharing the code before I go to bed. If I take more than 5 minutes to write this post, I fear I shall write nonsense something along the lines of how to count sheep in c#.)

The code I’m sharing can also load the layers. I just didn’t add anything to that. (Read the code. It’s well-written and hence easy to read.) If I cared about the layers, I’d probably have added a collection of images and a way of having the class easily do the boiler-plate code job of loading all of them. (Maybe I’ll add that in a part 2 post. I don’t really plan these things – I just write what’s important to me and on my mind at the moment.)

Actually it’s probably a really bad idea for an application’s default handling of all .psd files to be to export the layers. That’s fine for simple little files that us programmers create, with maybe 6 or 7 layers. (I’m assuming most programmers who are also comfortable with Photoshop have usage patterns similar to mine. Forgive me if I am wrong.) But designers are a different breed. Creativity and artistic inspiration can lead to files with many layers, limited only by the memory on their machines. And they may have glorious names like Layer 67 Copy 14. You don’t want to be automatically exporting .png files and pissing your users off.

My additions to Frank’s awesome code

Whenever I load images, I use either File.ReadAllBytes or my own async equivalent (depending whether the code I’m calling from is synchronous or asynchronous), then create a temporary MemoryStream around the image bytes, and load the image from the temporary stream, to return a copy of the image and avoid the risk of locking the file for the duration that the image is displayed. My async implementation just leverages the Stream’s async methods that were added in .Net 4.5 and gets the benefits of asynchronous IO.

But the PSDFile class that I downloaded doesn’t support loading from a Stream. It only has a parameterless constructor, and a Load method that loads a file. Of course it’s Load implementation uses a FileStream internally though. So my first change was to refactor Load into two public methods, the second one simply allows passing in a Stream. That is, all I did was select the code inside the using block when it loaded a file stream, and extract a new method; then made that method public after changing the parameter type from FileStream to Stream.

Next, I don’t want to go to the trouble of instantiating a PSDFile instance every time, then call Load; then Photoshop.ImageDecoder.Decode(psdFile). That’s a lot of trouble just to load an image. The obvious next step was thus to add two constructors, one accepting a filename and the other a stream, and have them internally load the composite image, which is then populated in a new public property. So that’s exactly what I did.

In the spirit of OCP, I only added the two new constructors. Calling the default constructor does not follow my introduced behaviour, and then even calling Dispose is unnecessary because the (Bitmap property’s memory) allocation didn’t happen. (Technically I had to add all three constructors, because the code as is didn’t even declare one.)

Unfortunately, the calling code can’t be a single line as I originally intended, because adding a public Image property (Image is disposable) necessitates implementing IDisposable, but it’s not too bad. Calling the code now is as simple as this:

 using (var psdFile = new PsdFile(filename))
 {
     image = psdFile.CompositImage.Clone() as Bitmap;
 }

The reason I call Clone is simply that my Dispose implementation destroys the image. I also followed the practice of declaring the CompositImage property as an Image (the base class for a Bitmap), even though I implemented it with a BitmapA best practice that comes naturally to me by now, yet I see it frequently forgotten in practice.

Unfortunately, the composite image that this code loads is not transparent.

The code downloads… I didn’t write a small application that just demos this code, but it is built in to my RomyView application. (Sorry, that download is getting rather large.) I also zipped the PSD parsing code. (Ok, so I didn’t create a small demo that uses it, but if you can’t figure out how to call the code yourself, you shouldn’t be a programmer. You should be a donkey.)

RomyView

Psd File Parser

And for interest sake, the code I use for loading all the image types I support in my application is now this:

using Photoshop;
using System;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;

namespace Romy.Core
{
    public static class ImageFile
    {
        /// <summary>Opens and returns an in-memory copy of the specified image, so as not to lock the file.</summary>
        public static Bitmap OpenBitmap(string filename)
        {
            Bitmap image = null;

            var disposeImageOnError = new Action(() =>
            {
                if (image != null)
                {
                    image.Dispose();
                    image = null;
                }
            });

            try
            {
                if (string.Compare(Path.GetExtension(filename), ".gif", StringComparison.InvariantCultureIgnoreCase) == 0)
                    image = Image.FromFile(filename) as Bitmap;
                else
                {
                    using (var stream = new MemoryStream(File.ReadAllBytes(filename)))
                    {
                        if (string.Compare(Path.GetExtension(filename), ".psd", StringComparison.InvariantCultureIgnoreCase) != 0)
                            image = new Bitmap(stream);
                        else
                        {
                            using (var psdFile = new PsdFile(stream))
                            {
                                image = psdFile.CompositImage.Clone() as Bitmap;
                            }
                        }
                    }
                }
            }
            catch (IOException) { disposeImageOnError(); }
            catch (UnauthorizedAccessException) { disposeImageOnError(); }
            catch (Exception ex)
            {
                ex.Log();
                disposeImageOnError();
            }

            return image;
        }

        /// <summary>Opens and returns a Bitmap using asynchronous IO, using the Task-based Asynchronous Pattern (TAP) pattern.
        public static async Task<Bitmap> OpenBitmapAsync(string filename)
        {
            Bitmap image = null;

            try
            {
                if (string.Compare(Path.GetExtension(filename), ".gif", StringComparison.InvariantCultureIgnoreCase) == 0)
                    image = Image.FromFile(filename) as Bitmap;
                else
                {
                    using (var memStream = new MemoryStream(await FileAsync.ReadAllBytesAsync(filename, Constants.LargeBufferSize)))
                    {
                        if (memStream.Length > 0) // My ReadAllBytesAsync method can return an empty array. Via Enumerable.Empty<byte>().ToArray()
                        {
                            if (string.Compare(Path.GetExtension(filename), ".psd", StringComparison.InvariantCultureIgnoreCase) != 0)
                                image = new Bitmap(memStream);
                            else
                            {
                                using (var psdFile = new PsdFile(memStream))
                                {
                                    image = psdFile.CompositImage.Clone() as Bitmap;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex) { ex.Log(); }

            return image;
        }
    }
}
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged . Bookmark the permalink.

3 Responses to Reading PSD files with c#

  1. Arav Singhal says:

    Hi Jerome,

    I love your work, it has helped me a lot. I have a couple of questions:

    First, is it alright if I make a maintainable GitHub repository for this library using your code? There were a couple of bugs in the skimpt library code (the PSD loader code) that I fixed, and since there have been a lot of people looking for a library online, this might be the best way to share it. Both skimpt and PSDPlugin have licenses (GPL v3 and MIT respectively) that allow me to share my modifications online. The only thing I need now is your permission. I’m also working on making this library async and free from unsafe code.

    Second, in a Xamarin.Mac GTK application, I’m not able to load the composite image properly, because the Bitmap constructor goes into some sort of infinite execution, and the next statement is never executed. Can you confirm if the library still works properly on a Windows system? The only machine I have access to while my dev machine is at the service center is a Mac.

    Thanks!

    Like

  2. Dennin Dalke Onorio says:

    Hey Arav Singhal, did you already published your changes in a repository? Could share the URL of your project, I’m interested on it. Thanks in advance!

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s