MadDugan

Spritesheet Export Plugin

Recommended Posts

7/24/2014 - v1.2.2 Minor Code change and recompile to support Paint.NET 4

 

I was in need of a consistent way to create simple, evenly spaced spritesheets from multiple layers in Paint.NET and I figured I would share the plugin.
 
DOWNLOAD: https://ssplugin.codeplex.com/releases/view/125730
 
This is a FileType plugin that will generate a PNG formatted file.
 
v1.2.1 -  Add honoring layer visibility.
v1.2.2  - Minor Code change and recompile to support Paint.NET 4

Installation Instructions

  • Verify Paint.NET is not running
  • Copy spritesheet.dll into the /Paint.NET/FileTypes sub-directory
  • Start Paint.NET and verify "SpriteSheet (*.ss.png)" is now an option for "Save as"

If there is a lot of interest, I will consider adding features, but as is, it suits my requirements.
 
Please cite if you use this tool for your application development and I will return the favor by linking to your application.
 
An example of multilayer sprite
post-102196-0-49478800-1364090376_thumb.
 
The resulting file created by exporter
post-102196-0-15765100-1364090385_thumb.

Edited by MadDugan
  • Like 1
  • Upvote 1

Share this post


Link to post
Share on other sites

Hi MadDugan - welcome to the forum :)

 

Your first plugin is very nicely done.  Works just as anticipated without hassle or fuss.  You've made a nice job of it.

 

You might want to mention in your post that it is a filetype plugin and the DLL should go in the /Filetypes/ folder.

Share this post


Link to post
Share on other sites

Hi MadDugan - welcome to the forum :)

 

Your first plugin is very nicely done.  Works just as anticipated without hassle or fuss.  You've made a nice job of it.

 

You might want to mention in your post that it is a filetype plugin and the DLL should go in the /Filetypes/ folder.

 

Thanks for the feedback.  I have made the changes as suggested.

Share this post


Link to post
Share on other sites

v1.2.1

Updated plugin to honor a layer's visibility flag

 

Scenerio where this would be used: Multiple sprite animations in one file for proper centering and resizing then only making visible layers you want to export.

Share this post


Link to post
Share on other sites

v1.2.1

Updated plugin to honor a layer's visibility flag

 

Scenerio where this would be used: Multiple sprite animations in one file for proper centering and resizing then only making visible layers you want to export.

I haven't used either of those, but I highly recommend this one.

Share this post


Link to post
Share on other sites

DennisW mentioned in the ImPDF thread that the SpriteSheet Export plugin is not working. I verfied this and he is right.

 

Maybe a moderator could mark the first post in the thread with 'Not Paint.NET 4 compatible'.

System.TypeLoadException: Could not load type 'PaintDotNet.GdiPlusFileType' from assembly 'PaintDotNet.Data, Version=4.2.5309.33059, Culture=neutral, PublicKeyToken=null'.

   at SpriteSheet.MyFileType.OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)

   at PaintDotNet.FileType.Save(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback, Boolean rememberToken) in d:\src\pdn\paintdotnet\src\Data\FileType.cs:line 284

   at PaintDotNet.Controls.DocumentWorkspace.<>c__DisplayClass30.<DoSave>b__28() in d:\src\pdn\paintdotnet\src\PaintDotNet\Controls\DocumentWorkspace.cs:line 2953

   at PaintDotNet.Functional.Func.Try(Action f) in d:\src\pdn\paintdotnet\src\Base\Functional\Func.cs:line 171

Share this post


Link to post
Share on other sites

This might help.

 

Hidden Content:

Share this post


Link to post
Share on other sites

This might help.

 

Hidden Content:
/////////////////////////////////////////////////////////////////////////////////
// paint.net                                                                   //
// Copyright (C) dotPDN LLC, Rick Brewster, and contributors.                  //
// All Rights Reserved.                                                        //
/////////////////////////////////////////////////////////////////////////////////
 
using PaintDotNet.SystemLayer;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
 
namespace PaintDotNet.Data
{
    /// <summary>
    /// Implements FileType for generic GDI+ codecs.
    /// </summary>
    /// <remarks>
    /// GDI+ file types do not support custom headers.
    /// </remarks>
    internal class GdiPlusFileType
        : FileType
    {
        private ImageFormat imageFormat; 
        public ImageFormat ImageFormat
        {
            get
            {
                return this.imageFormat;
            }
        }
 
        protected override void OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
        {
            GdiPlusFileType.Save(input, output, scratchSurface, this.ImageFormat, callback);
        }
 
        public static void Save(Document input, Stream output, Surface scratchSurface, ImageFormat format, ProgressEventHandler callback)
        {
            // flatten the document
            scratchSurface.Clear(ColorBgra.FromBgra(0, 0, 0, 0));
 
            using (RenderArgs ra = new RenderArgs(scratchSurface))
            {
                input.Render(ra, true);
            }
 
            using (Bitmap bitmap = scratchSurface.CreateAliasedBitmap())
            {
                LoadProperties(bitmap, input);
                bitmap.Save(output, format);
            }
        }
 
        public static void LoadProperties(Image dstImage, Document srcDoc)
        {
            LoadProperties(dstImage, srcDoc, _ => true);
        }
 
        public static void LoadProperties(Image dstImage, Document srcDoc, Func<PropertyItem, bool> selectorFn)
        {
            Bitmap asBitmap = dstImage as Bitmap;
 
            if (asBitmap != null)
            {
                // Sometimes GDI+ does not honor the resolution tags that we
                // put in manually via the EXIF properties.
                float dpiX;
                float dpiY;
 
                switch (srcDoc.DpuUnit)
                {
                    case MeasurementUnit.Centimeter:
                        dpiX = (float)Document.DotsPerCmToDotsPerInch(srcDoc.DpuX);
                        dpiY = (float)Document.DotsPerCmToDotsPerInch(srcDoc.DpuY);
                        break;
 
                    case MeasurementUnit.Inch:
                        dpiX = (float)srcDoc.DpuX;
                        dpiY = (float)srcDoc.DpuY;
                        break;
 
                    default:
                    case MeasurementUnit.Pixel:
                        dpiX = 1.0f;
                        dpiY = 1.0f;
                        break;
                }
 
                try
                {
                    asBitmap.SetResolution(dpiX, dpiY);
                }
 
                catch (Exception)
                {
                    // Ignore error
                }
            }
 
            Metadata metaData = srcDoc.Metadata;
 
            foreach (string key in metaData.GetKeys(Metadata.ExifSectionName))
            {
                string blob = metaData.GetValue(Metadata.ExifSectionName, key);
                PropertyItem pi = PdnGraphics.DeserializePropertyItem(blob);
 
                bool include = selectorFn(pi);
 
                if (include)
                {
                    try
                    {
                        dstImage.SetPropertyItem(pi);
                    }
 
                    catch (ArgumentException)
                    {
                        // Ignore error: the image does not support property items
                    }
                }
            }
        }
 
        protected override Document OnLoad(Stream input)
        {
            using (Image image = Image.FromStream(input, false, true))
            {
                Document document = Document.FromGdipImage(image, false);
                return document;
            }
        }
        
        public static ImageCodecInfo GetImageCodecInfo(ImageFormat format)
        {
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
 
            foreach (ImageCodecInfo icf in encoders)
            {
                if (icf.FormatID == format.Guid)
                {
                    return icf;
                }
            }
 
            return null;
        }
 
        public GdiPlusFileType(string name, ImageFormat imageFormat, bool supportsLayers, string[] extensions)
            : this(name, imageFormat, supportsLayers, extensions, false)
        {
        }
 
        public GdiPlusFileType(string name, ImageFormat imageFormat, bool supportsLayers, string[] extensions, bool savesWithProgress)
            : base(name, 
                   (supportsLayers ? FileTypeFlags.SupportsLayers : 0) | 
                       FileTypeFlags.SupportsLoading | 
                       FileTypeFlags.SupportsSaving | 
                       (savesWithProgress ? FileTypeFlags.SavesWithProgress : 0),
                   extensions)
        {
            this.imageFormat = imageFormat;
        }
    }
}

Exactly what I needed. Thanks!

Share this post


Link to post
Share on other sites

I tried to use the new version 1.22 and I get this error

 

System.TypeLoadException: Could not load type 'PaintDotNet.GdiPlusFileType' from assembly 'PaintDotNet.Data, Version=4.3.5316.40022, Culture=neutral, PublicKeyToken=null'.

   at SpriteSheet.MyFileType.OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)

   at PaintDotNet.FileType.Save(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback, Boolean rememberToken) in d:\src\pdn\paintdotnet\src\Data\FileType.cs:line 284

   at PaintDotNet.Controls.DocumentWorkspace.<>c__DisplayClass30.<DoSave>b__28() in d:\src\pdn\paintdotnet\src\PaintDotNet\Controls\DocumentWorkspace.cs:line 2954

   at PaintDotNet.Functional.Func.Try(Action f) in d:\src\pdn\paintdotnet\src\Base\Functional\Func.cs:line 174

 

My apologizes I checked things over and I found that the dll was not installed in the correct place. I corrected the install and low and behold it worked. Please forgive my error Great work nice to have it back again.
 
Dennis 
Edited by DennisW

Share this post


Link to post
Share on other sites

 

I tried to use the new version 1.22 and I get this error

System.TypeLoadException: Could not load type 'PaintDotNet.GdiPlusFileType' from assembly 'PaintDotNet.Data, Version=4.3.5316.40022, Culture=neutral, PublicKeyToken=null'.
   at SpriteSheet.MyFileType.OnSave(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback)
   at PaintDotNet.FileType.Save(Document input, Stream output, SaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback, Boolean rememberToken) in d:\src\pdn\paintdotnet\src\Data\FileType.cs:line 284
   at PaintDotNet.Controls.DocumentWorkspace.<>c__DisplayClass30.<DoSave>b__28() in d:\src\pdn\paintdotnet\src\PaintDotNet\Controls\DocumentWorkspace.cs:line 2954
   at PaintDotNet.Functional.Func.Try(Action f) in d:\src\pdn\paintdotnet\src\Base\Functional\Func.cs:line 174
My apologizes I checked things over and I found that the dll was not installed in the correct place. I corrected the install and low and behold it worked. Please forgive my error Great work nice to have it back again.
 
Dennis 

 

 

I got notified before your edit and immediately thought maybe it was still finding 1.2.1 somewhere.  Glad to see you resolved it.

 

-M

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now