dlemstra / Magick.NET

The .NET library for ImageMagick

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Create a resized copy of an image

toptensoftware opened this issue · comments

Is your feature request related to a problem? Please describe

I have a project that works with very large tif images. I need to keep the large image in memory for later processing, but I also need smaller versions for on-screen rendering. Currently to do this I need to duplicate the large image (doubling the memory usage) and then resize it to the smaller size.

Describe the solution you'd like

Would like the ability to directly create a resized copy of a source image (or part thereof)

Describe alternatives you've considered

As mentioned above, the current solution is to create copy of full image and then downsize it - but this requires more memory than directly resizing to a smaller image.

(Perhaps there's already a way to do this but if so, I couldn't figure out how)

Additional context

No response

In theory this could be possible for methods of ImageMagick that return a new image. It's an interesting idea but I will need to think about an API for this. And that will probably happen after I have added a new source code generator to call the native api.

Sounds good, I look forward to it.

Do you have any ideas how I could/should integrate this in the API? I think this behavior would only be required for methods that change the dimensions of an image. Otherwise you could just use .Clone() and change the image. I am now thinking about something like this:

using var image = new MagickImage("input.png");
using var thumbnail = image.NewMethod().Resize(100, 100);
using var thumbnail = image.NewProperty.Resize(100, 100);

The NewMethod() or NewProperty would return an interface that includes a the methods that change the dimensions of the image. But the disadvantage of this would be the discoverability in the api. So I am also thinking about something like this:

using var image = new MagickImage("input.png");
using var thumbnail = image.ResizeWithSuffix(100, 100);

As you can see besides deciding which option to use the naming is also something that I have to think about. Do you have any suggestions?

Not sure how feasible this is, and I realize this is adding to the original requirement, but the ideal for me would be something like this:

IMagickImage<QuantumType> CloneCropAndResize(IMagickGeometry? crop, IMagickGeometry? resize)

Where:

  • crop specifies which portion of the source image to grab. If null, the entire source image
  • resize specifies how to resize it into a new image instance. If null, no resizing.

ie: it would be the equivalent of the following but internally would combine all this into a single resize operation without the overhead of the full clone at the start.

image.Clone().Crop(crop).Resize(resize);

The nice thing about this is it would let you grab any region at any resolution. ie: you could grab tiled sections of a source image at display resolutions for rendering.

The name CloneCropAndResize is a bit wordy but sums up what it's doing. Alternative suggestion: ExtractImage, or maybe ExtractSubImage?

Those are not the only two methods this option will become available to. Creating a new method for each possible combination is not feasible.

Ah ok, I see what you mean.

Perhaps NewMethod() could be CloneThen().

var newImage = image.CloneThen().Resize(100, 100);

I guess the downside to this is it might be tempting to chain these together fluent style, but the result of the Crop call wouldn't be disposed.

var newImage = image
    .CloneThen().Crop(10, 10, 1000, 1000)
    .CloneThen().Resize(100, 100)

Thinking out loud (again no idea if this is feasible) but what if you could put together a chain of operations which you terminated with a function to actually do the work. ie: each intermediate operation just returned an interface (not an image instance) upon which you could perform additional operations. The Process() call at the end walks the chain of operations and produces a final image.

eg:

var newImage = image
    .CloneThen()
    .Crop(10, 10, 1000, 1000)
    .Resize(100, 100)
    .Whatever()
    .SomethingElse()
    .Process();

You're obviously thinking about this from a broader perspective than my narrow view... I'm sure whatever you come up with will be fine.

Good question. But I don’t think that new methods are needed, because it's already supported quite simply:

 using MagickImage image = new MagickImage(inputStream);
 using MagickImage thumbnail = image.Clone() as MagickImage;
 thumbnail.Resize(100, 100);

The Clone() method creates of copy of the pixels of the input image and then resizes that to the new dimensions. Here is an example what it does with the memory (the numbers are made up but should give you an idea of what happens):

flowchart TD
    A[Create image] --> B[10 mb used]
    B --> C[Clone]
    C --> D[20 mb used]
    D --> E[Resize to 50%]
    B --> F[Resize without clone]
    E --> G[15 mb used]
    F --> G

This means that with the new method the maximum amount of memory that is used is 15mb.