Skip to content

Arena-style image disposal? #271

@Arahizzz

Description

@Arahizzz

The current status quo of having to explicitly dispose of all temporary image handles is extremely unergonomic, especially as the logic becomes more complex.
Have you considered providing an arena object to manage the lifetimes of images as a single scope, similar to what Java's version of vips does?
I have experimented with this myself and implementation seems surprisingly easy, but requires upstream update of Image constructor:

public sealed class VipsArena : IDisposable
{
    private static readonly AsyncLocal<VipsArena?> Current = new AsyncLocal<VipsArena?>();

    private readonly List<Image> _images = new List<Image>();
    private readonly VipsArena? _parent;
    private bool _disposed;

    public VipsArena()
    {
        _parent = Current.Value;
        Current.Value = this;
    }

    /// <summary>
    /// Track an image in the current arena. Called automatically from Image constructor.
    /// </summary>
    internal static void Track(Image image)
    {
        Current.Value?._images.Add(image);
    }

    public void Dispose()
    {
        if (_disposed) return;
        _disposed = true;

        // Restore parent scope
        Current.Value = _parent;

        for (var i = _images.Count - 1; i >= 0; i--)
        {
            try
            {
                _images[i].Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error disposing image: {0}", e);
            }
        }
        _images.Clear();
    }
}
internal Image(nint pointer) : base(pointer)
{
    VipsArena.Track(this);
}

This substantially improves ergonomics, as you can now use any logic constructs without worrying about leaving dangling temp images behind:

using (var arena = new VipsArena())
{
    // no using needed here
    var image = Image.NewFromFile("input.png");

    // Conditionals
    if (image.HasAlpha())
    {
        image = image.Flatten();
    }
    
    // Method chaining
    image
        .Resize(0.5)
        .Gaussblur(1.5)
        .WriteToFile("output-1.png");
    
    // Multiple operators
    (image * 1.2 + 10).WriteToFile("output-2.png");
}

Would integrating something like this be possible in net-vips? As I understand it, this is not a breaking change, as you'll still be able to manage images the old way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions