From 4defbf4651c2909b7ac0c4089b67502a00666c79 Mon Sep 17 00:00:00 2001 From: Lehonti Ramos <17771375+Lehonti@users.noreply.github.com> Date: Tue, 10 Dec 2024 04:18:52 +0100 Subject: [PATCH] Disposing surfaces representing merged images in exporters (#1172) --- Pinta.Core/ImageFormats/GdkPixbufFormat.cs | 18 ++++++++---- .../ImageFormats/NetpbmPortablePixmap.cs | 11 +++++--- Pinta.Core/ImageFormats/TgaExporter.cs | 28 ++++++++++--------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/Pinta.Core/ImageFormats/GdkPixbufFormat.cs b/Pinta.Core/ImageFormats/GdkPixbufFormat.cs index 4b0d531040..76709260a3 100644 --- a/Pinta.Core/ImageFormats/GdkPixbufFormat.cs +++ b/Pinta.Core/ImageFormats/GdkPixbufFormat.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; +using Cairo; using GdkPixbuf; namespace Pinta.Core; @@ -49,7 +50,7 @@ public Document Import (Gio.File file) Layer layer = newDocument.Layers.AddNewLayer (file.GetDisplayName ()); - using Cairo.Context g = new (layer.Surface); + using Context g = new (layer.Surface); g.DrawPixbuf (effectiveBuffer, PointD.Zero); @@ -67,7 +68,11 @@ private static Pixbuf ReadPixbuf (Gio.File file) } } - protected virtual void DoSave (Pixbuf pb, Gio.File file, string fileType, Gtk.Window parent) + protected virtual void DoSave ( + Pixbuf pb, + Gio.File file, + string fileType, + Gtk.Window parent) { using Gio.OutputStream stream = file.Replace (); try { @@ -80,10 +85,13 @@ protected virtual void DoSave (Pixbuf pb, Gio.File file, string fileType, Gtk.Wi } } - public void Export (Document document, Gio.File file, Gtk.Window parent) + public void Export ( + Document document, + Gio.File file, + Gtk.Window parent) { - Cairo.ImageSurface surf = document.GetFlattenedImage (); - using Pixbuf pb = surf.ToPixbuf (); + using ImageSurface flattenedImage = document.GetFlattenedImage (); + using Pixbuf pb = flattenedImage.ToPixbuf (); DoSave (pb, file, filetype, parent); } } diff --git a/Pinta.Core/ImageFormats/NetpbmPortablePixmap.cs b/Pinta.Core/ImageFormats/NetpbmPortablePixmap.cs index 0b0f3a95d7..62ff050381 100644 --- a/Pinta.Core/ImageFormats/NetpbmPortablePixmap.cs +++ b/Pinta.Core/ImageFormats/NetpbmPortablePixmap.cs @@ -11,13 +11,13 @@ public sealed class NetpbmPortablePixmap : IImageExporter public void Export (ImageSurface flattenedImage, Stream outputStream) { using StreamWriter writer = new (outputStream, Encoding.ASCII) { - NewLine = "\n" // Always use LF endings to generate the same output on every platform and simplify unit tests + NewLine = "\n", // Always use LF endings to generate the same output on every platform and simplify unit tests }; Size imageSize = flattenedImage.GetSize (); ReadOnlySpan pixelData = flattenedImage.GetReadOnlyPixelData (); writer.WriteLine ("P3"); // Magic number for text-based portable pixmap format writer.WriteLine ($"{imageSize.Width} {imageSize.Height}"); - writer.WriteLine ("255"); + writer.WriteLine (byte.MaxValue); for (int row = 0; row < imageSize.Height; row++) { int rowStart = row * imageSize.Width; int rowEnd = rowStart + imageSize.Width; @@ -35,9 +35,12 @@ public void Export (ImageSurface flattenedImage, Stream outputStream) writer.Close (); } - public void Export (Document document, Gio.File file, Window parent) + public void Export ( + Document document, + Gio.File file, + Window parent) { - ImageSurface flattenedImage = document.GetFlattenedImage (); + using ImageSurface flattenedImage = document.GetFlattenedImage (); using GioStream outputStream = new (file.Replace ()); Export (flattenedImage, outputStream); } diff --git a/Pinta.Core/ImageFormats/TgaExporter.cs b/Pinta.Core/ImageFormats/TgaExporter.cs index af87594a6d..06cdcf1361 100644 --- a/Pinta.Core/ImageFormats/TgaExporter.cs +++ b/Pinta.Core/ImageFormats/TgaExporter.cs @@ -56,8 +56,7 @@ private record struct TgaHeader ( ushort imageWidth, // Image Width ushort imageHeight, // Image Height byte pixelDepth, // Pixel Depth - byte imageDesc // Image Descriptor - ) + byte imageDesc) // Image Descriptor { public readonly void WriteTo (BinaryWriter output) { @@ -87,11 +86,14 @@ public readonly void WriteTo (BinaryWriter output) // For now, we only export in uncompressed ARGB32 format. If someone requests this functionality, // we can always add more through an export dialog. - public void Export (Document document, Gio.File file, Gtk.Window parent) + public void Export ( + Document document, + Gio.File file, + Gtk.Window parent) { - ImageSurface surf = document.GetFlattenedImage (); // Assumes the surface is in ARGB32 format - using var file_stream = new GioStream (file.Replace ()); - using var writer = new BinaryWriter (file_stream); + using ImageSurface flattenedImage = document.GetFlattenedImage (); // Assumes the surface is in ARGB32 format + using GioStream file_stream = new (file.Replace ()); + using BinaryWriter writer = new (file_stream); TgaHeader header = new ( idLength: (byte) (ImageIdField.Length + 1), @@ -102,21 +104,21 @@ public void Export (Document document, Gio.File file, Gtk.Window parent) cmapEntrySize: 0, xOrigin: 0, yOrigin: 0, - imageWidth: (ushort) surf.Width, - imageHeight: (ushort) surf.Height, + imageWidth: (ushort) flattenedImage.Width, + imageHeight: (ushort) flattenedImage.Height, pixelDepth: 32, - imageDesc: 8 // 32-bit, lower-left origin, which is weird but hey... - ); + imageDesc: 8); // 32-bit, lower-left origin, which is weird but hey... + header.WriteTo (writer); writer.Write (ImageIdField); - Span data = surf.GetData (); + Span data = flattenedImage.GetData (); // It just so happens that the Cairo ARGB32 internal representation matches // the TGA format, except vertically-flipped. In little-endian, of course. - for (int y = surf.Height - 1; y >= 0; y--) - writer.Write (data.Slice (surf.Stride * y, surf.Stride)); + for (int y = flattenedImage.Height - 1; y >= 0; y--) + writer.Write (data.Slice (flattenedImage.Stride * y, flattenedImage.Stride)); } }