Skip to content

Commit

Permalink
Disposing surfaces representing merged images in exporters (#1172)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lehonti authored Dec 10, 2024
1 parent c6f56f1 commit 4defbf4
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 22 deletions.
18 changes: 13 additions & 5 deletions Pinta.Core/ImageFormats/GdkPixbufFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
// THE SOFTWARE.

using System;
using Cairo;
using GdkPixbuf;

namespace Pinta.Core;
Expand All @@ -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);

Expand All @@ -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 {
Expand All @@ -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);
}
}
11 changes: 7 additions & 4 deletions Pinta.Core/ImageFormats/NetpbmPortablePixmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ColorBgra> 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;
Expand All @@ -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);
}
Expand Down
28 changes: 15 additions & 13 deletions Pinta.Core/ImageFormats/TgaExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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),
Expand All @@ -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<byte> data = surf.GetData ();
Span<byte> 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));

}
}

0 comments on commit 4defbf4

Please sign in to comment.