MadDugan Posted March 24, 2013 Share Posted March 24, 2013 (edited) 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 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 The resulting file created by exporter Edited October 4, 2018 by toe_head2001 Added plugin as an attachment 1 1 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted March 24, 2013 Share Posted March 24, 2013 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. Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
MadDugan Posted March 24, 2013 Author Share Posted March 24, 2013 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. Quote Link to comment Share on other sites More sharing options...
MadDugan Posted March 26, 2013 Author Share Posted March 26, 2013 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. Quote Link to comment Share on other sites More sharing options...
claudekennilol Posted July 22, 2013 Share Posted July 22, 2013 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. Quote Link to comment Share on other sites More sharing options...
midora Posted July 21, 2014 Share Posted July 21, 2014 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 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted July 21, 2014 Share Posted July 21, 2014 I'll get on to this later today. I have a handful of plugins to check - SpriteSheet Export has been added to the list. Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
david.atwell Posted July 21, 2014 Share Posted July 21, 2014 Looks like BB already did the dirty work. Quote The Doctor: There was a goblin, or a trickster, or a warrior... A nameless, terrible thing, soaked in the blood of a billion galaxies. The most feared being in all the cosmos. And nothing could stop it, or hold it, or reason with it. One day it would just drop out of the sky and tear down your world.Amy: But how did it end up in there?The Doctor: You know fairy tales. A good wizard tricked it.River Song: I hate good wizards in fairy tales; they always turn out to be him. Link to comment Share on other sites More sharing options...
DennisW Posted July 23, 2014 Share Posted July 23, 2014 It would be great to see the problem with this plugin resolved. So it can work in V 4.02 Quote Link to comment Share on other sites More sharing options...
MadDugan Posted July 24, 2014 Author Share Posted July 24, 2014 Working on a compatibility fix Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted July 24, 2014 Share Posted July 24, 2014 This might help. ///////////////////////////////////////////////////////////////////////////////// // 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; } } } Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
MadDugan Posted July 24, 2014 Author Share Posted July 24, 2014 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! Quote Link to comment Share on other sites More sharing options...
DennisW Posted July 27, 2014 Share Posted July 27, 2014 (edited) 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 July 27, 2014 by DennisW Quote Link to comment Share on other sites More sharing options...
MadDugan Posted July 28, 2014 Author Share Posted July 28, 2014 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 Quote Link to comment Share on other sites More sharing options...
AlexDolmatov Posted August 4, 2014 Share Posted August 4, 2014 Thanks for the plug. Can make a plugin to save each layer in the file? Such exists, but the new version does not work. Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted August 4, 2014 Share Posted August 4, 2014 You mean LayerSaver? If there's a problem with it, post your question in the layersaver thread. Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
ZcheK Posted April 5, 2017 Share Posted April 5, 2017 Thanks for making this it's saving me many hours of manual alignment. Quote Link to comment Share on other sites More sharing options...
ZcheK Posted October 4, 2018 Share Posted October 4, 2018 (edited) Forgive my ignorance but how do I download this now? (new computer) I could only find the 'archive' file thru your link and that didn't have any .dll files. Edited October 4, 2018 by ZcheK Quote Link to comment Share on other sites More sharing options...
AndrewDavid Posted October 4, 2018 Share Posted October 4, 2018 Hi @ZcheK Welcome to the forum. Although it says archive - when you click on it it will prompt you to save a FIle with the extension .ZIP The ZIP file contains the DLL file which you need to extract once downloaded to your hard drive. Hope this helps Quote Link to comment Share on other sites More sharing options...
JLeno Posted October 4, 2018 Share Posted October 4, 2018 I just attempted to install this plugin as well. The .zip file contains no .dll files. Quote Link to comment Share on other sites More sharing options...
AndrewDavid Posted October 4, 2018 Share Posted October 4, 2018 (edited) @JLeno I just downloaded it to have a look and I see what you mean. Here is my copy. If @Ego Eram Reputo would be so kind to post it to the first entry, it should resolve any further headaches. Hope this helps Edited October 4, 2018 by toe_head2001 removed attachment; thanks 1 Quote Link to comment Share on other sites More sharing options...
JLeno Posted October 4, 2018 Share Posted October 4, 2018 @AndrewDavid Thanks! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.