Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a resized copy of an image #1577

Open
toptensoftware opened this issue Mar 7, 2024 · 8 comments
Open

Create a resized copy of an image #1577

toptensoftware opened this issue Mar 7, 2024 · 8 comments

Comments

@toptensoftware
Copy link

toptensoftware commented Mar 7, 2024

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

@dlemstra
Copy link
Owner

dlemstra commented Mar 8, 2024

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.

@toptensoftware
Copy link
Author

Sounds good, I look forward to it.

@dlemstra
Copy link
Owner

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?

@toptensoftware
Copy link
Author

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?

@dlemstra
Copy link
Owner

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

@toptensoftware
Copy link
Author

toptensoftware commented Mar 26, 2024

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.

@alexeygritsenko
Copy link

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);

@dlemstra
Copy link
Owner

dlemstra commented Mar 26, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants