I have problem with reading JPEG images in Java with help of Image IO in multithreaded environment. Problems only arises if several thread try to read image.
Symptoms vary from incorrect profile loading to exception:
java.awt.color.CMMException: LCMS error 13: Couldn't link the profiles
No matter how i read image, via ImageIO.read or by using ImageReader.
Source data (image) is completly isolated and immutable.
This problem can be related to: https://bugs.openjdk.java.net/browse/JDK-8041429 and https://bugs.openjdk.java.net/browse/JDK-8032243
The question is there any other way to read JPEG files with ImageIO with multiple threads. It seems like there is problem in ImageIO with sharing mutable state of the image color profiles that i have no control over. Only solution I see is completely isolating it on JVM level, which sounds like bad idea.
I use Oracle JDK 8u25. Changing JDK update version have no effect on the issue (not major version), i can't use JDK 7 without rewriting big chunks of the code.
Code for reference.
ImageInputStream input = new MemoryCacheImageInputStream(inputStream);
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
throw new IllegalArgumentException("No reader for: " + dataUuid.toString());
}
ImageReader reader = readers.next();
try {
reader.setInput(input);
BufferedImage image = reader.read(0, reader.getDefaultReadParam());
Add a hook on JVM start. In the hook, just put :
Class.forName("javax.imageio.ImageIO");
This will force the class loader to load the class and do whatever static initialization it needs. I think your problem is the class is being loaded on a thread, and the 2nd thread is trying to use ImageIO, which cause a clash on locks (or lackof locks) obtained on color profiles.
Edit: You can add this line to your main too. Make sure it's the first line you call. ImageIO was not the class responsible for ColorSpace initialization.
Class.forName("java.awt.color.ICC_ColorSpace");
Class.forName("sun.java2d.cmm.lcms.LCMS");
does the trick tough.
I had a similar multithreading problem with ImageIO yesterday and spent all day trying to figure out a solution (JDK 8u31 Win64). Even though I was not getting LCMS exceptions, the jpegs I read with ImageIO would have completely different colors. This happened only with jpegs with embedded color profiles and only when using ImageIO in multiple threads. An not always. Approximately 50% of the time. If it would start normally then it would continue properly reading all the rest of the images, but if it would not - all the rest would also be broken. So it was definetely color profile reading/conversion synchronization issue.
The trick with class loading proposed here did not help in my case.
The final solution was to use https://github.com/haraldk/TwelveMonkeys ImageIO jpeg plugin. I have tested it with thousands of jpegs in multiple threads and so far no issues.
Update
TwelveMonkeys plugin did not solve th e problem completely, still was getting exception. What helped is reverting to the old Kodak CMS by setting system property System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With