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

Decoding of lossless JPEG became slow #691

Closed
MichaelSchaich opened this issue Jul 19, 2022 · 6 comments
Closed

Decoding of lossless JPEG became slow #691

MichaelSchaich opened this issue Jul 19, 2022 · 6 comments

Comments

@MichaelSchaich
Copy link

Describe the bug
When updating Twelvemonkeys imageio from version 3.4.1 to version 3.8.2, decoding of lossless JPEG slowed down by a factor of almost 10.

Version information

  1. The version of the TwelveMonkeys ImageIO library in use.
    3.8.2; performance used to be ok with 3.4.1

  2. The exact output of java --version (or java -version for older Java releases).
    openjdk 11.0.14.1 2022-02-08 LTS
    OpenJDK Runtime Environment Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS)
    OpenJDK 64-Bit Server VM Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS, mixed mode)

  3. Extra information about OS version, server version, standalone program or web application packaging, executable wrapper, etc. Please state exact version numbers where applicable.
    OS: Microsoft Windows 10 Version 21H2 (Build 19044.1706)

To Reproduce
Steps to reproduce the behavior:

  1. Compile the below JUnit test sample code
  2. Download the sample image file jpegLossless.dcm (i found lossless compressed JPEG only wrapped in DICOM)
  3. Download ImageReaderFactory64Bit.properties and place it in resources\dicom. Needed to make sure the DicomImageReader uses the Twelvemonkeys JPEGImageReader for decoding JPEG.
  4. Run the JUnit test.
  5. If compiled with Twelvemonkeys version 3.8.2, i get for typical output
    testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader needed 2587 milliseconds to read testfiles/jpegLossless.dcm
    If compiled with Twelvemonkeys version 3.4.1, typical output times are like
    testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader needed 318 milliseconds to read testfiles/jpegLossless.dcm

Expected behavior
Decode times like with Twelvemonkeys version 3.4.1, i.e. around 300 milliseconds for the attached sample file instead of about 2000 milliseconds

Example code --------------------------------------------------------------------------------------------------------------
{
package com.agfa.hap.ddc.util;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.FileImageInputStream;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.dcm4che3.imageio.plugins.dcm.DicomImageReader;
import org.junit.Test;

public class TestImageReaderPerformance {

private static final Logger LOGGER = Logger.getLogger(TestImageReaderPerformance.class);
static {
	LOGGER.addAppender(new ConsoleAppender(new org.apache.log4j.PatternLayout(), "System.out"));
}


@Test
public void testReaderPerformance() throws Exception {
	// Configure to Load available imageReaders by using ImageIO
	System.setProperty("dcm4che.useImageIOServiceRegistry", "true");
	// Set the list of Readers to be used by dcm4che
	System.setProperty("org.dcm4che3.imageio.codec.ImageReaderFactory", "dicom/ImageReaderFactory64Bit.properties");
	try {
		String testfile = TestImageReaderPerformance.class.getResource("/testfiles/jpegLossless.dcm").getFile();
		ImageReader imageReader = null;
		Iterator<ImageReader> it  = ImageIO.getImageReadersBySuffix("jpg");
		it  = ImageIO.getImageReadersBySuffix("dcm");
		while (it.hasNext() ) {
			imageReader = it.next();
			if (imageReader != null) {
				Class<? extends ImageReader> clazz = imageReader.getClass();
				if (it.hasNext()) {
					//skip all DICOM reader except "org.dcm4che.imageio.plugins.dcm"
					if (!clazz.getPackage().getName().equalsIgnoreCase("org.dcm4che.imageio.plugins.dcm")){
						continue; //it's not the expected DICOM reader. Skip to the next one
					}
					//this DICOM reader is OK. Stop iteration and return this reader
					break;
				}
			}
		}
		assertNotNull(imageReader);
		String readerName = imageReader.getClass().getName();
		assertTrue("ImageReader should be org.dcm4che3.imageio.plugins.dcm.DicomImageReader, but is "+readerName, imageReader instanceof org.dcm4che3.imageio.plugins.dcm.DicomImageReader);
		imageReader.setInput(new FileImageInputStream(new File(testfile)));

		long time = System.currentTimeMillis();
		BufferedImage bi = imageReader.read(0);
		time = System.currentTimeMillis() - time;
		
		Field decompressorField = DicomImageReader.class.getDeclaredField("decompressor");
		decompressorField.setAccessible(true);
		ImageReader decompressor = (ImageReader)(decompressorField.get(imageReader));
		readerName = decompressor.getClass().getName();

		LOGGER.error("testReaderPerformance: ImageReader "+readerName+" needed "+time+" milliseconds to read "+testfile);
		assertNotNull(bi);
		long timeLimit = 1000;
		assertTrue("testReaderPerformance: Time to read "+testfile+": "+time+" exceeds "+timeLimit+" milliseconds", time<timeLimit);
	} catch (Exception exception) {
		fail();
	}
}

}
}
End example code --------------------------------------------------------------------------------------------------------------

** DicomImageReader configuration file ImageReaderFactory64Bit.properties**
ImageReaderFactory64Bit.zip

Image sample file jpegLossy.dcm
jpegLossy.zip

@haraldk
Copy link
Owner

haraldk commented Aug 2, 2022

Hi Michael,

I believe this is the same issue as #687, where the removal of the BufferedImageInputStream has led to a performance regression. I am working on creating replacement streams that will make this faster, but it will take some time...

In the meantime, things will go faster if you use a different stream implementation (see my comment in the other issue) if that is possible for your use case.

@haraldk
Copy link
Owner

haraldk commented Oct 15, 2022

New stream support is out in the 3.9.0 release. Feel free to give it a try and report back! 😀

@haraldk haraldk closed this as completed Oct 15, 2022
@MichaelSchaich
Copy link
Author

MichaelSchaich commented Jan 12, 2023

Hi Harald,
sorry for the late reply, i have been too busy with other tasks.
The perforance problem on decompressing lossless JEPG persists in Twelvemonkeys 3.9, checked for 3.9.0 and 3.9.4.
See attached file PerformanceDifferentVersions_JPEGLossless.txt, where i have added the new test results. I have a new machine and decoding is about 3 times faster, but still there is about a factor 10 between decoding times with twelvemonkeys versions 3.4 and 3.9.
ImageIO.setUseCache(false) made no difference.

@MichaelSchaich
Copy link
Author

Attaching failed, so i post the test results here:

Tests from July 2022 (typical values):
Bound with Twelvemonkeys version 3.4.1:
testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader needed 318 milliseconds to read /C:/SVN/DDC/branches/ddc-3.17.x/com.agfa.hap.ddc_core/target/test-classes/testfiles/jpegLossless.dcm

Bound with Twelvemonkeys version 3.8.2:
testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader needed 2587 milliseconds to read /C:/SVN/DDC/branches/ddc-3.17.x/com.agfa.hap.ddc_core/target/test-classes/testfiles/jpegLossless.dcm

Tests from Jan 11 2023, different machine, typical values:
Bound with Twelvemonkeys version 3.4.1:
testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@7216fb24 needed 105 milliseconds to read /C:/SVN/DDC/branches/ddc-3.18.x/com.agfa.hap.ddc_core/target/test-classes/testfiles/jpegLossless.dcm

Bound with Twelvemonkeys version 3.9.4:
testReaderPerformance: ImageReader com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@66ce957f needed 1240 milliseconds to read /C:/SVN/DDC/trunk/com.agfa.hap.ddc_core/target/test-classes/testfiles/jpegLossless.dcm

@MichaelSchaich
Copy link
Author

Hello Harald,
due to the vulnerability
'Found security vulnerability CVE-2021-23792 with severity >= 9 (severity = 9.8)' (see https://nvd.nist.gov/vuln/detail/CVE-2021-23792) and the issue #288 'Exif orientation' we cannot stick with twelvemonkeys version 3.4.1 much longer.
Thus, is there a chance for progress on this Lossless JPEG performance issue

@haraldk
Copy link
Owner

haraldk commented Apr 14, 2023

Hi Michael,

As your test case involves far more than just TwelveMonkeys, it's a bit hard for me to see exactly what makes things slow in your case. The stream you pass to the DICOM plugin and how the DICOM plugin uses the JPEG plugin might affect these things. I have very limited spare time these days, so anything you can do to make it easier to pinpoint, will also help resolve this faster.

I understand you want to upgrade to the latest version as soon a possible (I'm not sure I understand why 288 is relevant in this discussion).

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

2 participants