Memory usage for rotating jpeg

Hi,
We are looking for image rotatable library which consumes little memory.
We have use cases where users upload images as large as 500MB and wants to rotate. On rotating this image, can Aspose.Imaging handle this with little memory, or does it require 500MB memory?

@infra.yuki

Can you please specify the programming language you are using with Aspose.Imaging and any specific requirements for the rotation process?

We will be using java.
The only requirement is that it consumes little memory while rotating image.
Rotation will be done only by one of 90degrees, 180, 270, 360.

@infra.yuki Hello! If you’re concerned about memory usage during image processing, please check the BufferSizeHint property setting.

For Java

@evgeniy.sidenko @Alexey.Karpenko
Thank you for your help, and I have another question.

I tried rotating 158MB image with using below code, but gave me an error.
36MB image rotated fine.
I’m guessing there’s a limit on maximum pixels or size aspose.imaging can handle. If there is and you know, could you share what the limit is?

The image I used:

The code to rotate:

File file = new File("158MB.png");
try (Image img = Image.load(new FileInputStream(file));
		var fos = new FileOutputStream("out.png");
		var os = new BufferedOutputStream(fos);) {

	img.rotateFlip(RotateFlipType.Rotate90FlipNone);
	img.save(os);
}

The error given:

class com.aspose.imaging.internal.Exceptions.ArgumentOutOfRangeException: New capacity cannot be negative or less than the current capacity -2030567424 1698168832
Parameter name: value
com.aspose.imaging.system.io.MemoryStream.setCapacity(Unknown Source)
com.aspose.imaging.system.io.MemoryStream.b(Unknown Source)
com.aspose.imaging.system.io.MemoryStream.write(Unknown Source)
com.aspose.imaging.internal.bl.z$b.write(Unknown Source)
com.aspose.imaging.internal.bl.cy.write(Unknown Source)
com.aspose.imaging.StreamContainer.write(Unknown Source)
com.aspose.imaging.internal.kQ.g.process(Unknown Source)
com.aspose.imaging.internal.bl.bv$b.process(Unknown Source)
com.aspose.imaging.internal.bl.bX.process(Unknown Source)
com.aspose.imaging.internal.hr.i.process(Unknown Source)
com.aspose.imaging.internal.hq.a$a.b(Unknown Source)
com.aspose.imaging.internal.bl.bH.a(Unknown Source)
com.aspose.imaging.internal.bl.bH.a(Unknown Source)
com.aspose.imaging.internal.hq.a.a(Unknown Source)
com.aspose.imaging.internal.hq.a.loadRawData(Unknown Source)
com.aspose.imaging.internal.hq.a.loadPartialArgb32Pixels(Unknown Source)
com.aspose.imaging.internal.bl.bE.b(Unknown Source)
com.aspose.imaging.internal.bl.bH.a(Unknown Source)
com.aspose.imaging.internal.bl.bH.a(Unknown Source)
com.aspose.imaging.internal.bl.aZ.a(Unknown Source)
com.aspose.imaging.RasterImage.b(Unknown Source)
com.aspose.imaging.RasterImage.a(Unknown Source)
com.aspose.imaging.RasterImage.loadPartialArgb32Pixels(Unknown Source)
com.aspose.imaging.internal.bl.bv.a(Unknown Source)
com.aspose.imaging.RasterCachedImage.a(Unknown Source)
com.aspose.imaging.RasterCachedImage.rotateFlip(Unknown Source)
(I hid the line due to security reasons)
(I hid the line due to security reasons)
java.base/java.lang.reflect.Method.invoke(Method.java:580)
java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at com.aspose.imaging.system.io.MemoryStream.setCapacity(Unknown Source)
	at com.aspose.imaging.system.io.MemoryStream.b(Unknown Source)
	at com.aspose.imaging.system.io.MemoryStream.write(Unknown Source)
	at com.aspose.imaging.internal.bl.z$b.write(Unknown Source)
	at com.aspose.imaging.internal.bl.cy.write(Unknown Source)
	at com.aspose.imaging.StreamContainer.write(Unknown Source)
	at com.aspose.imaging.internal.kQ.g.process(Unknown Source)
	at com.aspose.imaging.internal.bl.bv$b.process(Unknown Source)
	at com.aspose.imaging.internal.bl.bX.process(Unknown Source)
	at com.aspose.imaging.internal.hr.i.process(Unknown Source)
	at com.aspose.imaging.internal.hq.a$a.b(Unknown Source)
	at com.aspose.imaging.internal.bl.bH.a(Unknown Source)
	at com.aspose.imaging.internal.bl.bH.a(Unknown Source)
	at com.aspose.imaging.internal.hq.a.a(Unknown Source)
	at com.aspose.imaging.internal.hq.a.loadRawData(Unknown Source)
	at com.aspose.imaging.internal.hq.a.loadPartialArgb32Pixels(Unknown Source)
	at com.aspose.imaging.internal.bl.bE.b(Unknown Source)
	at com.aspose.imaging.internal.bl.bH.a(Unknown Source)
	at com.aspose.imaging.internal.bl.bH.a(Unknown Source)
	at com.aspose.imaging.internal.bl.aZ.a(Unknown Source)
	at com.aspose.imaging.RasterImage.b(Unknown Source)
	at com.aspose.imaging.RasterImage.a(Unknown Source)
	at com.aspose.imaging.RasterImage.loadPartialArgb32Pixels(Unknown Source)
	at com.aspose.imaging.internal.bl.bv.a(Unknown Source)
	at com.aspose.imaging.RasterCachedImage.a(Unknown Source)
	at com.aspose.imaging.RasterCachedImage.rotateFlip(Unknown Source)
	(I hid the line due to security reasons)
	(I hid the line due to security reasons)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

aspose.imaging library: 24.12-jdk16.jar
jdk used: Oracle JDK 21.0.5
OS: windows 11 build 22631

@infra.yuki We are investigating this issue and will get back to you with an update shortly.

Hello, @infra.yuki
I confirm this bug. It will be fixed in the next release (25.2)
Thank you for sharing this issue. We regret you faced such a problem.
Best regards

@Alexey.Karpenko @evgeniy.sidenko
Thank you for confirming. I have another question.

I tried using LoadOptions#setBufferSizeHint, and noticed that setting setBufferSizeHint to positive value always lead to slow execution speed.

		var options = new LoadOptions();
		options.setBufferSizeHint(128);
		try (Image img = Image.load(new FileInputStream(file), options);
				var fos = new FileOutputStream("testOutput.png");
				var os = new BufferedOutputStream(fos);) {

			img.rotateFlip(RotateFlipType.Rotate90FlipNone);
		}
bufferSizeHint executionTime
-1 2.4s
1 23s
16 23s
128 23s
1024 23s
Integer.MAX_VALUE 23s

Image Used:
6MB.jpg (149.2 KB)

I expect when bufferSizeHint is large enough e.g. Integer.MAX_VALUE, execution time would be close to when it is set to bufferSizeHint.

aspose.imaging library: 24.12-jdk16.jar
jdk used: Oracle JDK 21.0.5
OS: windows 11 build 22631

@infra.yuki
You are right. Using the BufferSizeHint always leads to slower work, no matter what size you set. If BufferSizeHint is more than 0, the special work mode is used. Every allocation is in check; in most cases, disk storage is used instead of memory.