To convert a PSD file to PNG in C#, add the OneImage.Psd package, register its format and load the file like any other image, then save it as .png. You get the whole document as Photoshop composited it, and the same call converts to JPG or WebP or makes a thumbnail. To work with the layers themselves, PsdFile.Load returns the layer tree, which you can list, export, change, render and save back as a PSD. Everything is pure .NET code, with no Photoshop, ImageMagick or other native binaries, on Windows, Linux, macOS and in containers. Every sample was run against OneImage 1.10.2 on .NET 10.
dotnet add package RecursiveAI.OneImage dotnet add package RecursiveAI.OneImage.Psd
The examples use layer_effects.psd, an 800×640 Photoshop file with twelve layers that each show a layer effect, from the test files of the MIT-licensed psd-tools project.
Convert a PSD file to PNG
using OneImage; using OneImage.Psd; // PSD comes in its own package: register it once and reuse the options. var options = new LoadOptions { Configuration = new ImageConfiguration().Add(PsdFormat.Instance), }; // The merged image: the whole document as Photoshop composited it. Image.Load("layer_effects.psd", options).Save("layer_effects.png");
This wrote an 800×640 PNG of the whole design. PSD support lives in a separate package, so its format isn’t in OneImage’s default configuration: you add PsdFormat to an ImageConfiguration and pass it when you load. Saving needs nothing extra, because PNG, JPEG, WebP, GIF, TIFF, BMP and ICO are built in.
A PSD file can carry a merged copy of the whole document, and when it does, that is what Image.Load returns, so the result matches what Photoshop showed when the file was saved. A file without one is drawn from its layers instead. Large-document PSB files load the same way. Bitmap, gray, duotone, indexed, RGB, CMYK and Lab documents load; gray and RGB keep 8, 16 or 32 bits per channel, and CMYK and Lab are converted to RGB through the color engine.
Convert PSD to JPG or WebP, and make thumbnails
using OneImage; using OneImage.Psd; var options = new LoadOptions { Configuration = new ImageConfiguration().Add(PsdFormat.Instance), }; Image design = Image.Load("layer_effects.psd", options); // JPEG has no transparency: put the image on white first. design.Flatten(new Rgba32(255, 255, 255, 255)).Save("layer_effects.jpg"); // A 400 px wide WebP preview, in sRGB and without metadata. Image.Thumbnail(design, 400).Save("layer_effects-400.webp");
The JPEG is 800×640 and the WebP preview 400×320. Flatten puts a transparent design on a white background first, because JPEG can’t store transparency. Image.Thumbnail accepts a loaded image too, so the PSD format you registered applies. It resizes, converts to sRGB and leaves out metadata, which is what you want for web previews and asset browsers. Our page on converting images to WebP covers the quality settings.
Read the size of a PSD without decoding it
using OneImage; using OneImage.Psd; var options = new LoadOptions { Configuration = new ImageConfiguration().Add(PsdFormat.Instance), }; // Reads the header only. ImageInfo info = Image.Identify("layer_effects.psd", options); Console.WriteLine($"{info.Format.Name} {info.Width}x{info.Height}");
This printed psd 800x640 after reading only the header, which is a cheap check before you accept an upload or queue a conversion.
Read the layers of a PSD file
using OneImage.Layers; using OneImage.Psd; using PsdFile psd = PsdFile.Load("layer_effects.psd"); Console.WriteLine($"{psd.Document.Width}x{psd.Document.Height}, {psd.SourceColorMode}, {psd.SourceBitDepth}-bit"); // Walk the layer tree, groups included. void Print(GroupLayer group, int depth) { foreach (Layer layer in group.Children) { string hidden = layer.Visible ? "" : " (hidden)"; Console.WriteLine($"{new string(' ', depth * 2)}{layer.Kind} \"{layer.Name}\" {layer.Bounds.Width}x{layer.Bounds.Height}{hidden}"); if (layer is GroupLayer child) { Print(child, depth + 1); } } } Print(psd.Document.Root, 0);
800x640, Rgb, 8-bit Pixel "Background" 800x640 Pixel "Bevel" 190x47 Pixel "Emboss" 270x47 Pixel "Outer Glow" 399x48 Pixel "Inner Glow" 384x48 Pixel "Inner Shadow" 484x48 Pixel "Color Fill" 481x60 Pixel "Drop Shadow" 465x59 Pixel "Gradient Overlay" 600x60 Pixel "Pattern Overlay" 555x60 Pixel "Stroke" 232x48 Pixel "Satin" 180x48
PsdFile.Load parses the whole layer structure into a document model: pixel layers, groups, fill layers and adjustment layers, each with its name, visibility, opacity, blend mode, mask and bounds. Groups nest, so the sample walks them recursively. On a file with groups, such as the face drawing in the same test set, it printed the Group lines with their children indented below them. PsdFile is disposable, so wrap it in using.
Export each layer as a PNG
using OneImage.Layers; using OneImage.Psd; using PsdFile psd = PsdFile.Load("layer_effects.psd"); Directory.CreateDirectory("layers"); int index = 0; foreach (Layer layer in psd.Document.Root.Children) { index++; if (layer is PixelLayer pixelLayer) { // The layer's own pixels, at the size of the layer, not of the document. pixelLayer.Pixels.Snapshot().Save($"layers/{index:00} {layer.Name}.png"); } }
This wrote twelve PNGs: the 800×640 background and eleven text layers cut to their own bounds, such as 465×59 for “Drop Shadow”. A pixel layer’s Pixels is an editable canvas, and Snapshot() takes an immutable image of it at no cost. The export holds the layer’s own pixels, without the effects that are drawn when the document is composited. To place a layer back at its position in the document, its Bounds gives the offset. Layer names can contain characters that aren’t allowed in file names, so clean them up if your files come from users.
Hide a layer, render and save the PSD
using OneImage.Layers; using OneImage.Psd; using PsdFile psd = PsdFile.Load("layer_effects.psd"); // Hide the background and draw the document again from its layers. foreach (Layer layer in psd.Document.Root.Children) { if (layer.Name == "Background") { layer.Visible = false; } } psd.Document.Render().Save("no-background.png"); // Or keep it as a Photoshop file, with the change. psd.Save("no-background.psd");
Render() composites the document from its layers with blend modes, opacity, masks, clipping, adjustment layers and the common layer effects (drop and inner shadows, glows, strokes, overlays, bevels and satin), so the PNG shows the design without its gray background, on transparency. PsdFile.Save writes the change back to a Photoshop file. What the model doesn’t edit, such as text and smart objects, keeps its stored pixels and data and is written back unchanged. An independent PSD reader opened the saved file and showed its merged image with the background gone: the corner pixel that was gray is now transparent. The PSD documentation lists what is modelled in detail and how renders compare with Photoshop’s own composites.
PSD files from users
PSD is a large binary format, and a malformed file can claim huge layers or deep nesting in a few bytes. The reader is managed, bounds-checked code, and it checks every size against limits before allocating: at most 20,000 layers, 64 levels of group nesting and 64 MiB for one data block by default, plus OneImage’s usual pixel limits. A file over a limit fails with a typed exception instead of exhausting memory. To tighten them for uploads, pass a PsdLimits to new PsdFormat(...), or set PsdLimits and Limits on the PsdReadOptions you give PsdFile.Load.
Other ways to read PSD in C#
- Aspose.PSD is a commercial library that, in its NuGet description, manipulates PSD and PSB files and exports them to formats such as PNG, JPEG, GIF and TIFF. Its license is paid; see the Aspose.PSD price list.
- PsdSharp 1.2.0 (October 2025) is an MIT-licensed managed library that, in its NuGet description, reads and renders PSD and PSB files. It targets .NET Standard 2.0 and .NET 6, so it fits projects that can’t move to .NET 10.
OneImage reads SVG and PDF the same way, through the OneImage.Svg and OneImage.Pdf packages. For the core formats and operations, start at the OneImage overview.