8204187: Remove proprietary JPEG code from javax.imageio
Reviewed-by: bpb, serb, kaddepalli
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java Wed Jun 06 13:04:25 2018 -0700
@@ -187,13 +187,7 @@
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
+ public static final int JCS_YCCK = 5; // Y/Cb/Cr/K
public static final int NUM_JCS_CODES = JCS_YCCK+1;
@@ -212,22 +206,6 @@
public static class JCS {
public static final ColorSpace sRGB =
ColorSpace.getInstance(ColorSpace.CS_sRGB);
-
- private static ColorSpace YCC = null;
- private static boolean yccInited = false;
-
- public static ColorSpace getYCC() {
- if (!yccInited) {
- try {
- YCC = ColorSpace.getInstance(ColorSpace.CS_PYCC);
- } catch (IllegalArgumentException e) {
- // PYCC.pf may not always be installed
- } finally {
- yccInited = true;
- }
- }
- return YCC;
- }
}
// Default value for ImageWriteParam
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Wed Jun 06 13:04:25 2018 -0700
@@ -933,21 +933,6 @@
case JPEG.JCS_RGB:
list.add(raw);
list.add(getImageType(JPEG.JCS_GRAYSCALE));
- list.add(getImageType(JPEG.JCS_YCC));
- break;
- case JPEG.JCS_RGBA:
- list.add(raw);
- break;
- case JPEG.JCS_YCC:
- if (raw != null) { // Might be null if PYCC.pf not installed
- list.add(raw);
- list.add(getImageType(JPEG.JCS_RGB));
- }
- break;
- case JPEG.JCS_YCCA:
- if (raw != null) { // Might be null if PYCC.pf not installed
- list.add(raw);
- }
break;
case JPEG.JCS_YCbCr:
// As there is no YCbCr ColorSpace, we can't support
@@ -972,12 +957,6 @@
}
list.add(getImageType(JPEG.JCS_GRAYSCALE));
- list.add(getImageType(JPEG.JCS_YCC));
- break;
- case JPEG.JCS_YCbCrA: // Default is to convert to RGBA
- // As there is no YCbCr ColorSpace, we can't support
- // the raw type.
- list.add(getImageType(JPEG.JCS_RGBA));
break;
}
@@ -1065,36 +1044,6 @@
throw new IIOException("Incompatible color conversion");
}
break;
- case JPEG.JCS_RGBA:
- // No conversions available; image must be RGBA
- if ((csType != ColorSpace.TYPE_RGB) ||
- (cm.getNumComponents() != numComponents)) {
- throw new IIOException("Incompatible color conversion");
- }
- break;
- case JPEG.JCS_YCC:
- {
- ColorSpace YCC = JPEG.JCS.getYCC();
- if (YCC == null) { // We can't do YCC at all
- throw new IIOException("Incompatible color conversion");
- }
- if ((cs != YCC) &&
- (cm.getNumComponents() == numComponents)) {
- convert = new ColorConvertOp(YCC, cs, null);
- }
- }
- break;
- case JPEG.JCS_YCCA:
- {
- ColorSpace YCC = JPEG.JCS.getYCC();
- // No conversions available; image must be YCCA
- if ((YCC == null) || // We can't do YCC at all
- (cs != YCC) ||
- (cm.getNumComponents() != numComponents)) {
- throw new IIOException("Incompatible color conversion");
- }
- }
- break;
default:
// Anything else we can't handle at all
throw new IIOException("Incompatible color conversion");
@@ -1929,36 +1878,6 @@
DataBuffer.TYPE_BYTE,
false,
false);
- case JPEG.JCS_RGBA:
- return ImageTypeSpecifier.createPacked(JPEG.JCS.sRGB,
- 0xff000000,
- 0x00ff0000,
- 0x0000ff00,
- 0x000000ff,
- DataBuffer.TYPE_INT,
- false);
- case JPEG.JCS_YCC:
- if (JPEG.JCS.getYCC() != null) {
- return ImageTypeSpecifier.createInterleaved(
- JPEG.JCS.getYCC(),
- JPEG.bandOffsets[2],
- DataBuffer.TYPE_BYTE,
- false,
- false);
- } else {
- return null;
- }
- case JPEG.JCS_YCCA:
- if (JPEG.JCS.getYCC() != null) {
- return ImageTypeSpecifier.createInterleaved(
- JPEG.JCS.getYCC(),
- JPEG.bandOffsets[3],
- DataBuffer.TYPE_BYTE,
- true,
- false);
- } else {
- return null;
- }
default:
return null;
}
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Wed Jun 06 13:04:25 2018 -0700
@@ -754,115 +754,47 @@
}
break;
case ColorSpace.TYPE_RGB:
- if (!alpha) {
- if (jfif != null) {
+ if (jfif != null) {
+ outCsType = JPEG.JCS_YCbCr;
+ if (JPEG.isNonStandardICC(cs)
+ || ((cs instanceof ICC_ColorSpace)
+ && (jfif.iccSegment != null))) {
+ iccProfile =
+ ((ICC_ColorSpace) cs).getProfile();
+ }
+ } else if (adobe != null) {
+ switch (adobe.transform) {
+ case JPEG.ADOBE_UNKNOWN:
+ outCsType = JPEG.JCS_RGB;
+ break;
+ case JPEG.ADOBE_YCC:
outCsType = JPEG.JCS_YCbCr;
- if (JPEG.isNonStandardICC(cs)
- || ((cs instanceof ICC_ColorSpace)
- && (jfif.iccSegment != null))) {
- iccProfile =
- ((ICC_ColorSpace) cs).getProfile();
- }
- } else if (adobe != null) {
- switch (adobe.transform) {
- case JPEG.ADOBE_UNKNOWN:
- outCsType = JPEG.JCS_RGB;
- break;
- case JPEG.ADOBE_YCC:
+ break;
+ default:
+ warningOccurred
+ (WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
+ newAdobeTransform = JPEG.ADOBE_UNKNOWN;
+ outCsType = JPEG.JCS_RGB;
+ break;
+ }
+ } else {
+ // consult the ids
+ int outCS = sof.getIDencodedCSType();
+ // if they don't resolve it,
+ // consult the sampling factors
+ if (outCS != JPEG.JCS_UNKNOWN) {
+ outCsType = outCS;
+ } else {
+ boolean subsampled =
+ isSubsampled(sof.componentSpecs);
+ if (subsampled) {
outCsType = JPEG.JCS_YCbCr;
- break;
- default:
- warningOccurred
- (WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
- newAdobeTransform = JPEG.ADOBE_UNKNOWN;
- outCsType = JPEG.JCS_RGB;
- break;
- }
- } else {
- // consult the ids
- int outCS = sof.getIDencodedCSType();
- // if they don't resolve it,
- // consult the sampling factors
- if (outCS != JPEG.JCS_UNKNOWN) {
- outCsType = outCS;
} else {
- boolean subsampled =
- isSubsampled(sof.componentSpecs);
- if (subsampled) {
- outCsType = JPEG.JCS_YCbCr;
- } else {
- outCsType = JPEG.JCS_RGB;
- }
- }
- }
- } else { // RGBA
- if (jfif != null) {
- ignoreJFIF = true;
- warningOccurred
- (WARNING_IMAGE_METADATA_JFIF_MISMATCH);
- }
- if (adobe != null) {
- if (adobe.transform
- != JPEG.ADOBE_UNKNOWN) {
- newAdobeTransform = JPEG.ADOBE_UNKNOWN;
- warningOccurred
- (WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
- }
- outCsType = JPEG.JCS_RGBA;
- } else {
- // consult the ids
- int outCS = sof.getIDencodedCSType();
- // if they don't resolve it,
- // consult the sampling factors
- if (outCS != JPEG.JCS_UNKNOWN) {
- outCsType = outCS;
- } else {
- boolean subsampled =
- isSubsampled(sof.componentSpecs);
- outCsType = subsampled ?
- JPEG.JCS_YCbCrA : JPEG.JCS_RGBA;
+ outCsType = JPEG.JCS_RGB;
}
}
}
break;
- case ColorSpace.TYPE_3CLR:
- if (cs == JPEG.JCS.getYCC()) {
- if (!alpha) {
- if (jfif != null) {
- convertTosRGB = true;
- convertOp =
- new ColorConvertOp(cs,
- JPEG.JCS.sRGB,
- null);
- outCsType = JPEG.JCS_YCbCr;
- } else if (adobe != null) {
- if (adobe.transform
- != JPEG.ADOBE_YCC) {
- newAdobeTransform = JPEG.ADOBE_YCC;
- warningOccurred
- (WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
- }
- outCsType = JPEG.JCS_YCC;
- } else {
- outCsType = JPEG.JCS_YCC;
- }
- } else { // PhotoYCCA
- if (jfif != null) {
- ignoreJFIF = true;
- warningOccurred
- (WARNING_IMAGE_METADATA_JFIF_MISMATCH);
- } else if (adobe != null) {
- if (adobe.transform
- != JPEG.ADOBE_UNKNOWN) {
- newAdobeTransform
- = JPEG.ADOBE_UNKNOWN;
- warningOccurred
- (WARNING_IMAGE_METADATA_ADOBE_MISMATCH);
- }
- }
- outCsType = JPEG.JCS_YCCA;
- }
- }
}
}
} // else no dest, metadata, not an image. Defaults ok
@@ -1564,27 +1496,10 @@
retval = JPEG.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
- if (alpha) {
- retval = JPEG.JCS_RGBA;
- } else {
- retval = JPEG.JCS_RGB;
- }
+ retval = JPEG.JCS_RGB;
break;
case ColorSpace.TYPE_YCbCr:
- if (alpha) {
- retval = JPEG.JCS_YCbCrA;
- } else {
- retval = JPEG.JCS_YCbCr;
- }
- break;
- case ColorSpace.TYPE_3CLR:
- if (cs == JPEG.JCS.getYCC()) {
- if (alpha) {
- retval = JPEG.JCS_YCCA;
- } else {
- retval = JPEG.JCS_YCC;
- }
- }
+ retval = JPEG.JCS_YCbCr;
break;
case ColorSpace.TYPE_CMYK:
retval = JPEG.JCS_CMYK;
@@ -1604,27 +1519,10 @@
retval = JPEG.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
- if (alpha) {
- retval = JPEG.JCS_RGBA;
- } else {
- retval = JPEG.JCS_RGB;
- }
+ retval = JPEG.JCS_RGB;
break;
case ColorSpace.TYPE_YCbCr:
- if (alpha) {
- retval = JPEG.JCS_YCbCrA;
- } else {
- retval = JPEG.JCS_YCbCr;
- }
- break;
- case ColorSpace.TYPE_3CLR:
- if (cs == JPEG.JCS.getYCC()) {
- if (alpha) {
- retval = JPEG.JCS_YCCA;
- } else {
- retval = JPEG.JCS_YCC;
- }
- }
+ retval = JPEG.JCS_YCbCr;
break;
case ColorSpace.TYPE_CMYK:
retval = JPEG.JCS_CMYK;
@@ -1651,27 +1549,10 @@
retval = JPEG.JCS_GRAYSCALE;
break;
case ColorSpace.TYPE_RGB:
- if (alpha) {
- retval = JPEG.JCS_YCbCrA;
- } else {
- retval = JPEG.JCS_YCbCr;
- }
+ retval = JPEG.JCS_YCbCr;
break;
case ColorSpace.TYPE_YCbCr:
- if (alpha) {
- retval = JPEG.JCS_YCbCrA;
- } else {
- retval = JPEG.JCS_YCbCr;
- }
- break;
- case ColorSpace.TYPE_3CLR:
- if (cs == JPEG.JCS.getYCC()) {
- if (alpha) {
- retval = JPEG.JCS_YCCA;
- } else {
- retval = JPEG.JCS_YCC;
- }
- }
+ retval = JPEG.JCS_YCbCr;
break;
case ColorSpace.TYPE_CMYK:
retval = JPEG.JCS_YCCK;
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriterSpi.java Wed Jun 06 13:04:25 2018 -0700
@@ -73,7 +73,11 @@
public boolean canEncodeImage(ImageTypeSpecifier type) {
SampleModel sampleModel = type.getSampleModel();
+ ColorModel cm = type.getColorModel();
+ if (cm.hasAlpha()) {
+ return false;
+ }
// Find the maximum bit depth across all channels
int[] sampleSize = sampleModel.getSampleSize();
int bitDepth = sampleSize[0];
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java Wed Jun 06 13:04:25 2018 -0700
@@ -491,17 +491,6 @@
wantJFIF = false;
}
break;
- case ColorSpace.TYPE_3CLR:
- if (cs == JPEG.JCS.getYCC()) {
- wantJFIF = false;
- componentIDs[0] = (byte) 'Y';
- componentIDs[1] = (byte) 'C';
- componentIDs[2] = (byte) 'c';
- if (hasAlpha) {
- componentIDs[3] = (byte) 'A';
- }
- }
- break;
case ColorSpace.TYPE_YCbCr:
if (hasExtraComponents) { // e.g. K or alpha
wantJFIF = false;
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/SOFMarkerSegment.java Wed Jun 06 13:04:25 2018 -0700
@@ -182,29 +182,11 @@
switch(componentSpecs.length) {
case 3:
if ((componentSpecs[0].componentId == 'R')
- &&(componentSpecs[0].componentId == 'G')
- &&(componentSpecs[0].componentId == 'B')) {
+ &&(componentSpecs[1].componentId == 'G')
+ &&(componentSpecs[2].componentId == 'B')) {
return JPEG.JCS_RGB;
}
- if ((componentSpecs[0].componentId == 'Y')
- &&(componentSpecs[0].componentId == 'C')
- &&(componentSpecs[0].componentId == 'c')) {
- return JPEG.JCS_YCC;
- }
break;
- case 4:
- if ((componentSpecs[0].componentId == 'R')
- &&(componentSpecs[0].componentId == 'G')
- &&(componentSpecs[0].componentId == 'B')
- &&(componentSpecs[0].componentId == 'A')) {
- return JPEG.JCS_RGBA;
- }
- if ((componentSpecs[0].componentId == 'Y')
- &&(componentSpecs[0].componentId == 'C')
- &&(componentSpecs[0].componentId == 'c')
- &&(componentSpecs[0].componentId == 'A')) {
- return JPEG.JCS_YCCA;
- }
}
return JPEG.JCS_UNKNOWN;
--- a/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c Wed Jun 06 13:04:25 2018 -0700
@@ -1762,11 +1762,6 @@
}
}
break;
-#ifdef YCCALPHA
- case JCS_YCC:
- cinfo->out_color_space = JCS_YCC;
- break;
-#endif
case JCS_YCCK:
if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) {
/*
--- a/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c Wed Jun 06 12:51:44 2018 -0700
+++ b/src/java.desktop/share/native/libjavajpeg/jpegdecoder.c Wed Jun 06 13:04:25 2018 -0700
@@ -569,11 +569,7 @@
/* select buffered-image mode if it is a progressive JPEG only */
buffered_mode = cinfo.buffered_image = jpeg_has_multiple_scans(&cinfo);
grayscale = (cinfo.out_color_space == JCS_GRAYSCALE);
-#ifdef YCCALPHA
- hasalpha = (cinfo.out_color_space == JCS_RGBA);
-#else
hasalpha = 0;
-#endif
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (nor with the Java input source)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/imageio/plugins/jpeg/TestWriteARGBJPEG.java Wed Jun 06 13:04:25 2018 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8204187
+ * @run main TestWriteARGBJPEG
+ * @summary verify JPEG Alpha support is as reported.
+ */
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.io.ByteArrayOutputStream;
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriter;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+
+public class TestWriteARGBJPEG {
+ public static void main(String args[]) throws IOException {
+
+ BufferedImage bi =
+ new BufferedImage(10,10,BufferedImage.TYPE_INT_ARGB);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ // There should be no exception from the next line
+ // which internally should be relying on the canEncodeImage
+ // method which we'll also test directly.
+ boolean ret = ImageIO.write(bi, "jpeg", baos);
+ System.out.println("ImageIO.write(..) returned " + ret);
+
+ ImageTypeSpecifier its = new ImageTypeSpecifier(bi);
+ Iterator<ImageWriter> writers = ImageIO.getImageWriters(its, "jpeg");
+ boolean hasWriter = writers.hasNext();
+ // If this can't write it, an exception will be thrown.
+ if (writers.hasNext()) {
+ System.out.println("A writer was found.");
+ ImageWriter iw = writers.next();
+ MemoryCacheImageOutputStream mos =
+ new MemoryCacheImageOutputStream(baos);
+ iw.setOutput(mos);
+ iw.write(bi);
+ }
+
+ // Now Let's also ask the default JPEG writer's SPI if it
+ // can write an ARGB image.
+ ImageWriter iw = ImageIO.getImageWritersByFormatName("jpeg").next();
+ ImageWriterSpi iwSpi = iw.getOriginatingProvider();
+ boolean canEncode = iwSpi.canEncodeImage(bi);
+ System.out.println("SPI canEncodeImage returned " + canEncode);
+
+ // Now let's see if it is telling the truth.
+ try {
+ MemoryCacheImageOutputStream mos =
+ new MemoryCacheImageOutputStream(baos);
+ iw.setOutput(mos);
+ iw.write(bi);
+ } catch (IOException e) {
+ if (canEncode) {
+ throw e;
+ }
+ }
+ }
+}
--- a/test/jdk/javax/imageio/plugins/shared/BitDepth.java Wed Jun 06 12:51:44 2018 -0700
+++ b/test/jdk/javax/imageio/plugins/shared/BitDepth.java Wed Jun 06 13:04:25 2018 -0700
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4413109 4418221 6607198 8147448
+ * @bug 4413109 4418221 6607198 8147448 8204187
* @run main BitDepth
* @summary Checks that ImageIO writers for standard formats can handle
* various BufferedImage RGB types. An optional list of arguments
@@ -197,6 +197,7 @@
if (!writers.hasNext()) {
System.out.println("\tNo writers available for type " + biTypeNames[type]
+ " BufferedImage!");
+ return null;
} else {
ImageWriter writer = writers.next();
try (ImageOutputStream out = ImageIO.createImageOutputStream(file)) {
@@ -205,7 +206,7 @@
} catch (Exception e) {
System.out.println("\tCan't write a type " + biTypeNames[type]
+ " BufferedImage!");
- return null;
+ throw new RuntimeException(e);
}
}