This project has moved. For the latest updates, please go here.

PSDs, PNGs and Transparency

Oct 29, 2014 at 7:17 PM
Hi, I'm new to Magick.NET and ImageMagick, and I'm wondering if there is any documentation anywhere for Magick.NET beyond the few simple examples. Specifically I'm trying to figure out how to deal with transparencies. I'm not finding the API very straight forward, and the method signature descriptions in Visual Studio are pretty generic. I've been looking at the ImageMagick documentation, but I'm having trouble relating the command line arguments to Magick.NET APIs (and even the ImageMagick docs seem quite obscure). Or maybe I'm just too much of an IM newb.

Anyway, I'm loading a multi-layer PSD, which I need to turn into 2 PNGs. The first PNG is just the top (last) layer of the PSD, and the second PNG is the full PSD. The issues I'm having is that:

A. On both PNG files, the white area is transparent in the PNG, and the transparent area is white (i.e. the wrong area is transparent). I've tried to correct this, but either I end up with an all black PNG, or an all transparent PNG.

B. On the PNG created from multiple layers, lines that are solid black or red in the PSD appear as transparent, with a faint trace around them. Plus problem "A" above.

This is my code at the moment:

string fileName = image.ImageKey.Substring(0, image.ImageKey.LastIndexOf("."));
            using (MagickImageCollection collection = new MagickImageCollection(image.Image))
            {
                using (MagickImage topLayer = collection[collection.Count - 1])
                {
                    //collection.Remove(topLayer);

                    MagickImageInfo info = new MagickImageInfo(image.Image);

                    topLayer.BackgroundColor = new MagickColor(255,255,255);
                    bool hasAlpha = topLayer.HasAlpha;
                    //topLayer.Alpha(AlphaOption.Background);
                    topLayer.AlphaColor = new MagickColor(255,255,255);
                    //.ColorAlpha(new MagickColor(255, 255, 255));
                    //topLayer.Opaque(new MagickColor(255, 255, 255, 255), new MagickColor(0, 0, 0));
                    //topLayer.Transparent(new MagickColor(255, 255, 255));
                    topLayer.Write(path + fileName + "_toplayer.png");
                }

                collection.Coalesce();
                using (MagickImage bottomLayer = collection[0])
                {
                    bottomLayer.BackgroundColor = MagickColor.Transparent;
                    bottomLayer.Write(path + fileName + "_bottomlayer.png");
                }
            }
Any input is greatly appreciated :)

Thanks,
Mike
Coordinator
Oct 30, 2014 at 1:49 PM
Can you post a link to your PSD image? Feel free to contact me through CodePlex if you don't wan to publicly share your image.
Coordinator
Nov 1, 2014 at 1:23 PM
Thanks for e-mailing me the image. I just copy pasted the help from the Magick++ header files to the summary of Magic.NET so it could probably use some improvements. I always check the examples at "http://www.imagemagick.org/Usage" if I need some more information for one of the ImageMagick options.

If you read the PSD image in a collection the first image is the 'full PSD' so you should remove the call to Coalesce and just write that image as the bottom layer. If I understand you correctly you want to change the white colors to transparent and put the image on a white background. I hope the following example does what you want:
static void ChangeBackground(MagickImage image)
{
  // For now you will have to change the image from CMYK to RGB.
  // I am working on a fix for this.
  image.AddProfile(ColorProfile.SRGB);
  image.ColorSpace = ColorSpace.sRGB;
  
  // First change the white color to a color that is not in the image.
  MagickColor white = new MagickColor("white");
  MagickColor purple = new MagickColor("purple");
  image.Opaque(white, purple);
  
  // Draw the image on a white background.
  using (MagickImage background = new MagickImage(white, image.Width, image.Height))
  {
    image.Composite(background, Gravity.Center, CompositeOperator.DstOver);
  }
  
  // Change the purple pixels to transparent
  image.Opaque(purple, MagickColor.Transparent);
}

static void ExtractLayers()
{
  var image = GetImage();
  using (MagickImageCollection collection = new MagickImageCollection(image.Image))
  {
    // Don't use using because the collection will take care of Disposing the images.
    MagickImage bottom = collection[0];
    ChangeBackground(bottom);
    bottom.Write("bottomlayer.png");
    
    MagickImage top = collection[collection.Count - 1];
    ChangeBackground(top);
    top.Write("toplayer.png");
  }
}
Coordinator
Nov 3, 2014 at 7:10 PM
This turned out to be a bug in the PSD reader of ImageMagick 7. This will be fixed in the next release of Magick.NET (7.0.0.0007).
Nov 10, 2014 at 11:18 PM
Dirk, thanks so much for your help with the issues I was having. I'm now happily importing, separating and processing multi-layer PSD files!

Thanks for all the tips, and the quick turn-around in fixing the PSD reader bug! I'll be sure to make a donation to this great project when I get my project out the door!