-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
7u67, 8
-
x86
-
windows_7
FULL PRODUCT VERSION :
JDK 7 and JDK 8, all updates
ADDITIONAL OS VERSION INFORMATION :
Windows 7 32 and 64 bit, Linux, etc
A DESCRIPTION OF THE PROBLEM :
JPEGImageWriter fails writing CMYK / YCCK files because of a mismatch in constant definitions between Java code and native C code.
com.sun.imageio.plugins.jpeg.JPEG defines a set of constants for JPEG color spaces:
// IJG Color codes.
public static final int JCS_UNKNOWN = 0; // error/unspecified
public static final int JCS_GRAYSCALE = 1; // monochrome
public static final int JCS_RGB = 2; // red/green/blue
public static final int JCS_YCbCr = 3; // Y/Cb/Cr (also known as YUV)
public static final int JCS_CMYK = 4; // C/M/Y/K
public static final int JCS_YCC = 5; // PhotoYCC
public static final int JCS_RGBA = 6; // RGB-Alpha
public static final int JCS_YCbCrA = 7; // Y/Cb/Cr/Alpha
// 8 and 9 were old "Legacy" codes which the old code never identified
// on reading anyway. Support for writing them is being dropped, too.
public static final int JCS_YCCA = 10; // PhotoYCC-Alpha
public static final int JCS_YCCK = 11; // Y/Cb/Cr/K
On the native code, these constants are defined in jpeglib.h as:
typedef enum {
JCS_UNKNOWN, /* error/unspecified */
JCS_GRAYSCALE, /* monochrome */
JCS_RGB, /* red/green/blue */
JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
JCS_CMYK, /* C/M/Y/K */
JCS_YCCK /* Y/Cb/Cr/K */
} J_COLOR_SPACE;
The values of these constants in C is implied by the order of the enum declaration, as 0, 1, 2, 3, 4 and 5.
0 to 4 match with the Java constracts, but JCS_YCCK == 11 in Java and == 5 in the native code.
When the native code is about to compress and write a JPEG file, it checks the color space to make sure that it is in range, and it does so by checking for:
inCs > JCS_YCCK or outCs > JCS_YCCK
If the Java code passes Java's JCS_YCCK (a valid value), this fails validation in the native code, even though it should be fine. i.e. Java passes 11, which is not < 5, and therefore an exception is thrown.
The validation and exception in the C code happens in imageioJPEG.c ->Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage().
Resolution is simple (and good programming practice), the enum definition in the native code should use the option to hard code the constant values, to make them match the constant values in the JPEG code:
typedef enum {
JCS_UNKNOWN = 0, /* error/unspecified */
JCS_GRAYSCALE = 1, /* monochrome */
JCS_RGB = 2, /* red/green/blue */
JCS_YCbCr = 3, /* Y/Cb/Cr (also known as YUV) */
JCS_CMYK = 4, /* C/M/Y/K */
JCS_YCCK = 11 /* Y/Cb/Cr/K */
} J_COLOR_SPACE;
ADDITIONAL REGRESSION INFORMATION:
This was working correctly in Java 6. The reason is that Java 6 native code had additional entries in the enum definition, and therefore the constant values matched those in Java.
The values were still implied, but because they were the same number of constants in the enum, they happened to match.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a CMYK image in Java and try to write it as a JPEG using ImageIO. We can provide source code if necessary that works in Java 6, but not in Java 7 or Java 8.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The JPEG image should be written out without errors.
ACTUAL -
Exception is thrown by native method.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
IIOException: Invalid argument to native writeImage
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
When a BufferedImage is passed to this method of type CMYK:
public static void saveCMYKJPEG(OutputStream outStream, BufferedImage image, int xdpi, int ydpi, float quality) throws PDFException, IOException
{
// get a JPEG writer
Iterator encoders = ImageIO.getImageWritersByFormatName("JPEG");
if (encoders.hasNext() == false)
{
throw new PDFException ("No JPEG Writers Available.");
}
// Get the first writer
ImageWriter writer = (ImageWriter)encoders.next();
ImageWriteParam param = writer.getDefaultWriteParam();
// Set compression quality
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(image);
param.setDestinationType(imageType);
// Write the image
writer.setOutput(new MemoryCacheImageOutputStream (outStream));
writer.write(null, new IIOImage(image.getRaster(), null, null), param);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None found.
JDK 7 and JDK 8, all updates
ADDITIONAL OS VERSION INFORMATION :
Windows 7 32 and 64 bit, Linux, etc
A DESCRIPTION OF THE PROBLEM :
JPEGImageWriter fails writing CMYK / YCCK files because of a mismatch in constant definitions between Java code and native C code.
com.sun.imageio.plugins.jpeg.JPEG defines a set of constants for JPEG color spaces:
// IJG Color codes.
public static final int JCS_UNKNOWN = 0; // error/unspecified
public static final int JCS_GRAYSCALE = 1; // monochrome
public static final int JCS_RGB = 2; // red/green/blue
public static final int JCS_YCbCr = 3; // Y/Cb/Cr (also known as YUV)
public static final int JCS_CMYK = 4; // C/M/Y/K
public static final int JCS_YCC = 5; // PhotoYCC
public static final int JCS_RGBA = 6; // RGB-Alpha
public static final int JCS_YCbCrA = 7; // Y/Cb/Cr/Alpha
// 8 and 9 were old "Legacy" codes which the old code never identified
// on reading anyway. Support for writing them is being dropped, too.
public static final int JCS_YCCA = 10; // PhotoYCC-Alpha
public static final int JCS_YCCK = 11; // Y/Cb/Cr/K
On the native code, these constants are defined in jpeglib.h as:
typedef enum {
JCS_UNKNOWN, /* error/unspecified */
JCS_GRAYSCALE, /* monochrome */
JCS_RGB, /* red/green/blue */
JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
JCS_CMYK, /* C/M/Y/K */
JCS_YCCK /* Y/Cb/Cr/K */
} J_COLOR_SPACE;
The values of these constants in C is implied by the order of the enum declaration, as 0, 1, 2, 3, 4 and 5.
0 to 4 match with the Java constracts, but JCS_YCCK == 11 in Java and == 5 in the native code.
When the native code is about to compress and write a JPEG file, it checks the color space to make sure that it is in range, and it does so by checking for:
inCs > JCS_YCCK or outCs > JCS_YCCK
If the Java code passes Java's JCS_YCCK (a valid value), this fails validation in the native code, even though it should be fine. i.e. Java passes 11, which is not < 5, and therefore an exception is thrown.
The validation and exception in the C code happens in imageioJPEG.c ->Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage().
Resolution is simple (and good programming practice), the enum definition in the native code should use the option to hard code the constant values, to make them match the constant values in the JPEG code:
typedef enum {
JCS_UNKNOWN = 0, /* error/unspecified */
JCS_GRAYSCALE = 1, /* monochrome */
JCS_RGB = 2, /* red/green/blue */
JCS_YCbCr = 3, /* Y/Cb/Cr (also known as YUV) */
JCS_CMYK = 4, /* C/M/Y/K */
JCS_YCCK = 11 /* Y/Cb/Cr/K */
} J_COLOR_SPACE;
ADDITIONAL REGRESSION INFORMATION:
This was working correctly in Java 6. The reason is that Java 6 native code had additional entries in the enum definition, and therefore the constant values matched those in Java.
The values were still implied, but because they were the same number of constants in the enum, they happened to match.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a CMYK image in Java and try to write it as a JPEG using ImageIO. We can provide source code if necessary that works in Java 6, but not in Java 7 or Java 8.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The JPEG image should be written out without errors.
ACTUAL -
Exception is thrown by native method.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
IIOException: Invalid argument to native writeImage
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
When a BufferedImage is passed to this method of type CMYK:
public static void saveCMYKJPEG(OutputStream outStream, BufferedImage image, int xdpi, int ydpi, float quality) throws PDFException, IOException
{
// get a JPEG writer
Iterator encoders = ImageIO.getImageWritersByFormatName("JPEG");
if (encoders.hasNext() == false)
{
throw new PDFException ("No JPEG Writers Available.");
}
// Get the first writer
ImageWriter writer = (ImageWriter)encoders.next();
ImageWriteParam param = writer.getDefaultWriteParam();
// Set compression quality
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(image);
param.setDestinationType(imageType);
// Write the image
writer.setOutput(new MemoryCacheImageOutputStream (outStream));
writer.write(null, new IIOImage(image.getRaster(), null, null), param);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None found.
- duplicates
-
JDK-7044758 test/closed/javax/imageio/plugins/jpeg/JpegPremultAlphaTest.java fails on OpenJDK
-
- Closed
-