1.1 --- a/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java Thu Jun 25 12:10:01 2009 -0700
1.2 +++ b/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageWriter.java Mon Jun 29 14:42:22 2009 -0700
1.3 @@ -506,6 +506,19 @@
1.4
1.5 writeFileHeader(fileSize, offset);
1.6
1.7 + /* According to MSDN description, the top-down image layout
1.8 + * is allowed only if compression type is BI_RGB or BI_BITFIELDS.
1.9 + * Images with any other compression type must be wrote in the
1.10 + * bottom-up layout.
1.11 + */
1.12 + if (compressionType == BMPConstants.BI_RGB ||
1.13 + compressionType == BMPConstants.BI_BITFIELDS)
1.14 + {
1.15 + isTopDown = bmpParam.isTopDown();
1.16 + } else {
1.17 + isTopDown = false;
1.18 + }
1.19 +
1.20 writeInfoHeader(headerSize, bitsPerPixel);
1.21
1.22 // compression
1.23 @@ -588,8 +601,6 @@
1.24 return;
1.25 }
1.26
1.27 - isTopDown = bmpParam.isTopDown();
1.28 -
1.29 int maxBandOffset = bandOffsets[0];
1.30 for (int i = 1; i < bandOffsets.length; i++)
1.31 if (bandOffsets[i] > maxBandOffset)
1.32 @@ -1299,7 +1310,7 @@
1.33 stream.writeInt(w);
1.34
1.35 // height
1.36 - stream.writeInt(h);
1.37 + stream.writeInt(isTopDown ? -h : h);
1.38
1.39 // number of planes
1.40 stream.writeShort(1);
2.1 --- a/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java Thu Jun 25 12:10:01 2009 -0700
2.2 +++ b/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java Mon Jun 29 14:42:22 2009 -0700
2.3 @@ -27,6 +27,8 @@
2.4
2.5 import java.awt.Point;
2.6 import java.awt.Rectangle;
2.7 +import java.io.IOException;
2.8 +import javax.imageio.stream.ImageInputStream;
2.9
2.10 /**
2.11 * This class contains utility methods that may be useful to ImageReader
2.12 @@ -198,4 +200,17 @@
2.13 vals, 1);
2.14 return vals;
2.15 }
2.16 +
2.17 + public static int readMultiByteInteger(ImageInputStream iis)
2.18 + throws IOException
2.19 + {
2.20 + int value = iis.readByte();
2.21 + int result = value & 0x7f;
2.22 + while((value & 0x80) == 0x80) {
2.23 + result <<= 7;
2.24 + value = iis.readByte();
2.25 + result |= (value & 0x7f);
2.26 + }
2.27 + return result;
2.28 + }
2.29 }
3.1 --- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java Thu Jun 25 12:10:01 2009 -0700
3.2 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEG.java Mon Jun 29 14:42:22 2009 -0700
3.3 @@ -215,17 +215,21 @@
3.4 public static class JCS {
3.5 public static final ColorSpace sRGB =
3.6 ColorSpace.getInstance(ColorSpace.CS_sRGB);
3.7 - public static final ColorSpace YCC;
3.8
3.9 - static {
3.10 - ColorSpace cs = null;
3.11 - try {
3.12 - cs = ColorSpace.getInstance(ColorSpace.CS_PYCC);
3.13 - } catch (IllegalArgumentException e) {
3.14 - // PYCC.pf may not always be installed
3.15 - } finally {
3.16 - YCC = cs;
3.17 + private static ColorSpace YCC = null;
3.18 + private static boolean yccInited = false;
3.19 +
3.20 + public static ColorSpace getYCC() {
3.21 + if (!yccInited) {
3.22 + try {
3.23 + YCC = ColorSpace.getInstance(ColorSpace.CS_PYCC);
3.24 + } catch (IllegalArgumentException e) {
3.25 + // PYCC.pf may not always be installed
3.26 + } finally {
3.27 + yccInited = true;
3.28 + }
3.29 }
3.30 + return YCC;
3.31 }
3.32 }
3.33
4.1 --- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Thu Jun 25 12:10:01 2009 -0700
4.2 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java Mon Jun 29 14:42:22 2009 -0700
4.3 @@ -41,6 +41,7 @@
4.4 import java.awt.color.ColorSpace;
4.5 import java.awt.color.ICC_Profile;
4.6 import java.awt.color.ICC_ColorSpace;
4.7 +import java.awt.color.CMMException;
4.8 import java.awt.image.BufferedImage;
4.9 import java.awt.image.Raster;
4.10 import java.awt.image.WritableRaster;
4.11 @@ -53,6 +54,7 @@
4.12 import java.util.List;
4.13 import java.util.Iterator;
4.14 import java.util.ArrayList;
4.15 +import java.util.NoSuchElementException;
4.16
4.17 import sun.java2d.Disposer;
4.18 import sun.java2d.DisposerRecord;
4.19 @@ -215,51 +217,6 @@
4.20 /** The DisposerRecord that handles the actual disposal of this reader. */
4.21 private DisposerRecord disposerRecord;
4.22
4.23 - /**
4.24 - * Maintain an array of the default image types corresponding to the
4.25 - * various supported IJG colorspace codes.
4.26 - */
4.27 - private static final ImageTypeSpecifier [] defaultTypes =
4.28 - new ImageTypeSpecifier [JPEG.NUM_JCS_CODES];
4.29 -
4.30 - static {
4.31 - defaultTypes[JPEG.JCS_GRAYSCALE] =
4.32 - ImageTypeSpecifier.createFromBufferedImageType
4.33 - (BufferedImage.TYPE_BYTE_GRAY);
4.34 - defaultTypes[JPEG.JCS_RGB] =
4.35 - ImageTypeSpecifier.createInterleaved
4.36 - (JPEG.JCS.sRGB,
4.37 - JPEG.bOffsRGB,
4.38 - DataBuffer.TYPE_BYTE,
4.39 - false,
4.40 - false);
4.41 - defaultTypes[JPEG.JCS_RGBA] =
4.42 - ImageTypeSpecifier.createPacked
4.43 - (JPEG.JCS.sRGB,
4.44 - 0xff000000,
4.45 - 0x00ff0000,
4.46 - 0x0000ff00,
4.47 - 0x000000ff,
4.48 - DataBuffer.TYPE_INT,
4.49 - false);
4.50 - if (JPEG.JCS.YCC != null) {
4.51 - defaultTypes[JPEG.JCS_YCC] =
4.52 - ImageTypeSpecifier.createInterleaved
4.53 - (JPEG.JCS.YCC,
4.54 - JPEG.bandOffsets[2],
4.55 - DataBuffer.TYPE_BYTE,
4.56 - false,
4.57 - false);
4.58 - defaultTypes[JPEG.JCS_YCCA] =
4.59 - ImageTypeSpecifier.createInterleaved
4.60 - (JPEG.JCS.YCC,
4.61 - JPEG.bandOffsets[3],
4.62 - DataBuffer.TYPE_BYTE,
4.63 - true,
4.64 - false);
4.65 - }
4.66 - }
4.67 -
4.68 /** Sets up static C structures. */
4.69 private static native void initReaderIDs(Class iisClass,
4.70 Class qTableClass,
4.71 @@ -673,6 +630,17 @@
4.72 !java.util.Arrays.equals(oldData, newData))
4.73 {
4.74 iccCS = new ICC_ColorSpace(newProfile);
4.75 + // verify new color space
4.76 + try {
4.77 + float[] colors = iccCS.fromRGB(new float[] {1f, 0f, 0f});
4.78 + } catch (CMMException e) {
4.79 + /*
4.80 + * Embedded profile seems to be corrupted.
4.81 + * Ignore this profile.
4.82 + */
4.83 + iccCS = null;
4.84 + warningOccurred(WARNING_IGNORE_INVALID_ICC);
4.85 + }
4.86 }
4.87 }
4.88
4.89 @@ -706,11 +674,11 @@
4.90 * Return an ImageTypeSpecifier corresponding to the given
4.91 * color space code, or null if the color space is unsupported.
4.92 */
4.93 - private ImageTypeSpecifier getImageType(int code) {
4.94 - ImageTypeSpecifier ret = null;
4.95 + private ImageTypeProducer getImageType(int code) {
4.96 + ImageTypeProducer ret = null;
4.97
4.98 if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) {
4.99 - ret = defaultTypes[code];
4.100 + ret = ImageTypeProducer.getTypeProducer(code);
4.101 }
4.102 return ret;
4.103 }
4.104 @@ -724,7 +692,7 @@
4.105 }
4.106
4.107 // Returns null if it can't be represented
4.108 - return getImageType(colorSpaceCode);
4.109 + return getImageType(colorSpaceCode).getType();
4.110 } finally {
4.111 clearThreadLock();
4.112 }
4.113 @@ -758,13 +726,13 @@
4.114
4.115 // Get the raw ITS, if there is one. Note that this
4.116 // won't always be the same as the default.
4.117 - ImageTypeSpecifier raw = getImageType(colorSpaceCode);
4.118 + ImageTypeProducer raw = getImageType(colorSpaceCode);
4.119
4.120 // Given the encoded colorspace, build a list of ITS's
4.121 // representing outputs you could handle starting
4.122 // with the default.
4.123
4.124 - ArrayList list = new ArrayList(1);
4.125 + ArrayList<ImageTypeProducer> list = new ArrayList<ImageTypeProducer>(1);
4.126
4.127 switch (colorSpaceCode) {
4.128 case JPEG.JCS_GRAYSCALE:
4.129 @@ -774,9 +742,7 @@
4.130 case JPEG.JCS_RGB:
4.131 list.add(raw);
4.132 list.add(getImageType(JPEG.JCS_GRAYSCALE));
4.133 - if (JPEG.JCS.YCC != null) {
4.134 - list.add(getImageType(JPEG.JCS_YCC));
4.135 - }
4.136 + list.add(getImageType(JPEG.JCS_YCC));
4.137 break;
4.138 case JPEG.JCS_RGBA:
4.139 list.add(raw);
4.140 @@ -801,19 +767,21 @@
4.141 list.add(getImageType(JPEG.JCS_RGB));
4.142
4.143 if (iccCS != null) {
4.144 - list.add(ImageTypeSpecifier.createInterleaved
4.145 + list.add(new ImageTypeProducer() {
4.146 + protected ImageTypeSpecifier produce() {
4.147 + return ImageTypeSpecifier.createInterleaved
4.148 (iccCS,
4.149 JPEG.bOffsRGB, // Assume it's for RGB
4.150 DataBuffer.TYPE_BYTE,
4.151 false,
4.152 - false));
4.153 + false);
4.154 + }
4.155 + });
4.156
4.157 }
4.158
4.159 list.add(getImageType(JPEG.JCS_GRAYSCALE));
4.160 - if (JPEG.JCS.YCC != null) { // Might be null if PYCC.pf not installed
4.161 - list.add(getImageType(JPEG.JCS_YCC));
4.162 - }
4.163 + list.add(getImageType(JPEG.JCS_YCC));
4.164 break;
4.165 case JPEG.JCS_YCbCrA: // Default is to convert to RGBA
4.166 // As there is no YCbCr ColorSpace, we can't support
4.167 @@ -822,7 +790,7 @@
4.168 break;
4.169 }
4.170
4.171 - return list.iterator();
4.172 + return new ImageTypeIterator(list.iterator());
4.173 }
4.174
4.175 /**
4.176 @@ -872,6 +840,10 @@
4.177 if (csType == ColorSpace.TYPE_RGB) { // We want RGB
4.178 // IJG can do this for us more efficiently
4.179 setOutColorSpace(structPointer, JPEG.JCS_RGB);
4.180 + // Update java state according to changes
4.181 + // in the native part of decoder.
4.182 + outColorSpaceCode = JPEG.JCS_RGB;
4.183 + numComponents = 3;
4.184 } else if (csType != ColorSpace.TYPE_GRAY) {
4.185 throw new IIOException("Incompatible color conversion");
4.186 }
4.187 @@ -881,6 +853,10 @@
4.188 if (colorSpaceCode == JPEG.JCS_YCbCr) {
4.189 // If the jpeg space is YCbCr, IJG can do it
4.190 setOutColorSpace(structPointer, JPEG.JCS_GRAYSCALE);
4.191 + // Update java state according to changes
4.192 + // in the native part of decoder.
4.193 + outColorSpaceCode = JPEG.JCS_GRAYSCALE;
4.194 + numComponents = 1;
4.195 }
4.196 } else if ((iccCS != null) &&
4.197 (cm.getNumComponents() == numComponents) &&
4.198 @@ -906,20 +882,26 @@
4.199 }
4.200 break;
4.201 case JPEG.JCS_YCC:
4.202 - if (JPEG.JCS.YCC == null) { // We can't do YCC at all
4.203 - throw new IIOException("Incompatible color conversion");
4.204 - }
4.205 - if ((cs != JPEG.JCS.YCC) &&
4.206 - (cm.getNumComponents() == numComponents)) {
4.207 - convert = new ColorConvertOp(JPEG.JCS.YCC, cs, null);
4.208 + {
4.209 + ColorSpace YCC = JPEG.JCS.getYCC();
4.210 + if (YCC == null) { // We can't do YCC at all
4.211 + throw new IIOException("Incompatible color conversion");
4.212 + }
4.213 + if ((cs != YCC) &&
4.214 + (cm.getNumComponents() == numComponents)) {
4.215 + convert = new ColorConvertOp(YCC, cs, null);
4.216 + }
4.217 }
4.218 break;
4.219 case JPEG.JCS_YCCA:
4.220 - // No conversions available; image must be YCCA
4.221 - if ((JPEG.JCS.YCC == null) || // We can't do YCC at all
4.222 - (cs != JPEG.JCS.YCC) ||
4.223 - (cm.getNumComponents() != numComponents)) {
4.224 - throw new IIOException("Incompatible color conversion");
4.225 + {
4.226 + ColorSpace YCC = JPEG.JCS.getYCC();
4.227 + // No conversions available; image must be YCCA
4.228 + if ((YCC == null) || // We can't do YCC at all
4.229 + (cs != YCC) ||
4.230 + (cm.getNumComponents() != numComponents)) {
4.231 + throw new IIOException("Incompatible color conversion");
4.232 + }
4.233 }
4.234 break;
4.235 default:
4.236 @@ -1554,3 +1536,140 @@
4.237 }
4.238 }
4.239 }
4.240 +
4.241 +/**
4.242 + * An internal helper class that wraps producer's iterator
4.243 + * and extracts specifier instances on demand.
4.244 + */
4.245 +class ImageTypeIterator implements Iterator<ImageTypeSpecifier> {
4.246 + private Iterator<ImageTypeProducer> producers;
4.247 + private ImageTypeSpecifier theNext = null;
4.248 +
4.249 + public ImageTypeIterator(Iterator<ImageTypeProducer> producers) {
4.250 + this.producers = producers;
4.251 + }
4.252 +
4.253 + public boolean hasNext() {
4.254 + if (theNext != null) {
4.255 + return true;
4.256 + }
4.257 + if (!producers.hasNext()) {
4.258 + return false;
4.259 + }
4.260 + do {
4.261 + theNext = producers.next().getType();
4.262 + } while (theNext == null && producers.hasNext());
4.263 +
4.264 + return (theNext != null);
4.265 + }
4.266 +
4.267 + public ImageTypeSpecifier next() {
4.268 + if (theNext != null || hasNext()) {
4.269 + ImageTypeSpecifier t = theNext;
4.270 + theNext = null;
4.271 + return t;
4.272 + } else {
4.273 + throw new NoSuchElementException();
4.274 + }
4.275 + }
4.276 +
4.277 + public void remove() {
4.278 + producers.remove();
4.279 + }
4.280 +}
4.281 +
4.282 +/**
4.283 + * An internal helper class that provides means for deferred creation
4.284 + * of ImageTypeSpecifier instance required to describe available
4.285 + * destination types.
4.286 + *
4.287 + * This implementation only supports standard
4.288 + * jpeg color spaces (defined by corresponding JCS color space code).
4.289 + *
4.290 + * To support other color spaces one can override produce() method to
4.291 + * return custom instance of ImageTypeSpecifier.
4.292 + */
4.293 +class ImageTypeProducer {
4.294 +
4.295 + private ImageTypeSpecifier type = null;
4.296 + boolean failed = false;
4.297 + private int csCode;
4.298 +
4.299 + public ImageTypeProducer(int csCode) {
4.300 + this.csCode = csCode;
4.301 + }
4.302 +
4.303 + public ImageTypeProducer() {
4.304 + csCode = -1; // undefined
4.305 + }
4.306 +
4.307 + public synchronized ImageTypeSpecifier getType() {
4.308 + if (!failed && type == null) {
4.309 + try {
4.310 + type = produce();
4.311 + } catch (Throwable e) {
4.312 + failed = true;
4.313 + }
4.314 + }
4.315 + return type;
4.316 + }
4.317 +
4.318 + private static final ImageTypeProducer [] defaultTypes =
4.319 + new ImageTypeProducer [JPEG.NUM_JCS_CODES];
4.320 +
4.321 + public synchronized static ImageTypeProducer getTypeProducer(int csCode) {
4.322 + if (csCode < 0 || csCode >= JPEG.NUM_JCS_CODES) {
4.323 + return null;
4.324 + }
4.325 + if (defaultTypes[csCode] == null) {
4.326 + defaultTypes[csCode] = new ImageTypeProducer(csCode);
4.327 + }
4.328 + return defaultTypes[csCode];
4.329 + }
4.330 +
4.331 + protected ImageTypeSpecifier produce() {
4.332 + switch (csCode) {
4.333 + case JPEG.JCS_GRAYSCALE:
4.334 + return ImageTypeSpecifier.createFromBufferedImageType
4.335 + (BufferedImage.TYPE_BYTE_GRAY);
4.336 + case JPEG.JCS_RGB:
4.337 + return ImageTypeSpecifier.createInterleaved(JPEG.JCS.sRGB,
4.338 + JPEG.bOffsRGB,
4.339 + DataBuffer.TYPE_BYTE,
4.340 + false,
4.341 + false);
4.342 + case JPEG.JCS_RGBA:
4.343 + return ImageTypeSpecifier.createPacked(JPEG.JCS.sRGB,
4.344 + 0xff000000,
4.345 + 0x00ff0000,
4.346 + 0x0000ff00,
4.347 + 0x000000ff,
4.348 + DataBuffer.TYPE_INT,
4.349 + false);
4.350 + case JPEG.JCS_YCC:
4.351 + if (JPEG.JCS.getYCC() != null) {
4.352 + return ImageTypeSpecifier.createInterleaved(
4.353 + JPEG.JCS.getYCC(),
4.354 + JPEG.bandOffsets[2],
4.355 + DataBuffer.TYPE_BYTE,
4.356 + false,
4.357 + false);
4.358 + } else {
4.359 + return null;
4.360 + }
4.361 + case JPEG.JCS_YCCA:
4.362 + if (JPEG.JCS.getYCC() != null) {
4.363 + return ImageTypeSpecifier.createInterleaved(
4.364 + JPEG.JCS.getYCC(),
4.365 + JPEG.bandOffsets[3],
4.366 + DataBuffer.TYPE_BYTE,
4.367 + true,
4.368 + false);
4.369 + } else {
4.370 + return null;
4.371 + }
4.372 + default:
4.373 + return null;
4.374 + }
4.375 + }
4.376 +}
5.1 --- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Thu Jun 25 12:10:01 2009 -0700
5.2 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java Mon Jun 29 14:42:22 2009 -0700
5.3 @@ -812,7 +812,7 @@
5.4 }
5.5 break;
5.6 case ColorSpace.TYPE_3CLR:
5.7 - if (cs == JPEG.JCS.YCC) {
5.8 + if (cs == JPEG.JCS.getYCC()) {
5.9 if (!alpha) {
5.10 if (jfif != null) {
5.11 convertTosRGB = true;
5.12 @@ -1494,7 +1494,7 @@
5.13 }
5.14 break;
5.15 case ColorSpace.TYPE_3CLR:
5.16 - if (cs == JPEG.JCS.YCC) {
5.17 + if (cs == JPEG.JCS.getYCC()) {
5.18 if (alpha) {
5.19 retval = JPEG.JCS_YCCA;
5.20 } else {
5.21 @@ -1533,7 +1533,7 @@
5.22 }
5.23 break;
5.24 case ColorSpace.TYPE_3CLR:
5.25 - if (cs == JPEG.JCS.YCC) {
5.26 + if (cs == JPEG.JCS.getYCC()) {
5.27 if (alpha) {
5.28 retval = JPEG.JCS_YCCA;
5.29 } else {
5.30 @@ -1579,7 +1579,7 @@
5.31 }
5.32 break;
5.33 case ColorSpace.TYPE_3CLR:
5.34 - if (cs == JPEG.JCS.YCC) {
5.35 + if (cs == JPEG.JCS.getYCC()) {
5.36 if (alpha) {
5.37 retval = JPEG.JCS_YCCA;
5.38 } else {
6.1 --- a/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java Thu Jun 25 12:10:01 2009 -0700
6.2 +++ b/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java Mon Jun 29 14:42:22 2009 -0700
6.3 @@ -490,7 +490,7 @@
6.4 }
6.5 break;
6.6 case ColorSpace.TYPE_3CLR:
6.7 - if (cs == JPEG.JCS.YCC) {
6.8 + if (cs == JPEG.JCS.getYCC()) {
6.9 wantJFIF = false;
6.10 componentIDs[0] = (byte) 'Y';
6.11 componentIDs[1] = (byte) 'C';
7.1 --- a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java Thu Jun 25 12:10:01 2009 -0700
7.2 +++ b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java Mon Jun 29 14:42:22 2009 -0700
7.3 @@ -45,6 +45,7 @@
7.4 import java.util.Iterator;
7.5
7.6 import com.sun.imageio.plugins.common.I18N;
7.7 +import com.sun.imageio.plugins.common.ReaderUtil;
7.8
7.9 /** This class is the Java Image IO plugin reader for WBMP images.
7.10 * It may subsample the image, clip the image,
7.11 @@ -141,11 +142,11 @@
7.12 metadata.wbmpType = wbmpType;
7.13
7.14 // Read image width
7.15 - width = readMultiByteInteger();
7.16 + width = ReaderUtil.readMultiByteInteger(iis);
7.17 metadata.width = width;
7.18
7.19 // Read image height
7.20 - height = readMultiByteInteger();
7.21 + height = ReaderUtil.readMultiByteInteger(iis);
7.22 metadata.height = height;
7.23
7.24 gotHeader = true;
7.25 @@ -311,17 +312,6 @@
7.26 gotHeader = false;
7.27 }
7.28
7.29 - private int readMultiByteInteger() throws IOException {
7.30 - int value = iis.readByte();
7.31 - int result = value & 0x7f;
7.32 - while((value & 0x80) == 0x80) {
7.33 - result <<= 7;
7.34 - value = iis.readByte();
7.35 - result |= (value & 0x7f);
7.36 - }
7.37 - return result;
7.38 - }
7.39 -
7.40 /*
7.41 * This method verifies that given byte is valid wbmp type marker.
7.42 * At the moment only 0x0 marker is described by wbmp spec.
8.1 --- a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java Thu Jun 25 12:10:01 2009 -0700
8.2 +++ b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java Mon Jun 29 14:42:22 2009 -0700
8.3 @@ -33,9 +33,13 @@
8.4 import java.io.IOException;
8.5 import javax.imageio.ImageReader;
8.6 import javax.imageio.IIOException;
8.7 +import com.sun.imageio.plugins.common.ReaderUtil;
8.8
8.9 public class WBMPImageReaderSpi extends ImageReaderSpi {
8.10
8.11 + private static final int MAX_WBMP_WIDTH = 1024;
8.12 + private static final int MAX_WBMP_HEIGHT = 768;
8.13 +
8.14 private static String [] writerSpiNames =
8.15 {"com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi"};
8.16 private static String[] formatNames = {"wbmp", "WBMP"};
8.17 @@ -79,16 +83,44 @@
8.18 }
8.19
8.20 ImageInputStream stream = (ImageInputStream)source;
8.21 - byte[] b = new byte[3];
8.22
8.23 stream.mark();
8.24 - stream.readFully(b);
8.25 + int type = stream.readByte(); // TypeField
8.26 + int fixHeaderField = stream.readByte();
8.27 + // check WBMP "header"
8.28 + if (type != 0 || fixHeaderField != 0) {
8.29 + // while WBMP reader does not support ext WBMP headers
8.30 + stream.reset();
8.31 + return false;
8.32 + }
8.33 +
8.34 + int width = ReaderUtil.readMultiByteInteger(stream);
8.35 + int height = ReaderUtil.readMultiByteInteger(stream);
8.36 + // check image dimension
8.37 + if (width <= 0 || height <= 0) {
8.38 + stream.reset();
8.39 + return false;
8.40 + }
8.41 +
8.42 + long dataLength = stream.length();
8.43 + if (dataLength == -1) {
8.44 + // We can't verify that amount of data in the stream
8.45 + // corresponds to image dimension because we do not know
8.46 + // the length of the data stream.
8.47 + // Assuming that wbmp image are used for mobile devices,
8.48 + // let's introduce an upper limit for image dimension.
8.49 + // In case if exact amount of raster data is unknown,
8.50 + // let's reject images with dimension above the limit.
8.51 + stream.reset();
8.52 + return (width < MAX_WBMP_WIDTH) && (height < MAX_WBMP_HEIGHT);
8.53 + }
8.54 +
8.55 + dataLength -= stream.getStreamPosition();
8.56 stream.reset();
8.57
8.58 - return ((b[0] == (byte)0) && // TypeField == 0
8.59 - b[1] == 0 && // FixHeaderField == 0xxx00000; not support ext header
8.60 - ((b[2] & 0x8f) != 0 || (b[2] & 0x7f) != 0)); // First width byte
8.61 - //XXX: b[2] & 0x8f) != 0 for the bug in Sony Ericsson encoder.
8.62 + long scanSize = (width / 8) + ((width % 8) == 0 ? 0 : 1);
8.63 +
8.64 + return (dataLength == scanSize * height);
8.65 }
8.66
8.67 public ImageReader createReaderInstance(Object extension)
9.1 --- a/src/share/classes/java/awt/Font.java Thu Jun 25 12:10:01 2009 -0700
9.2 +++ b/src/share/classes/java/awt/Font.java Mon Jun 29 14:42:22 2009 -0700
9.3 @@ -445,18 +445,19 @@
9.4 */
9.5 private AttributeValues getAttributeValues() {
9.6 if (values == null) {
9.7 - values = new AttributeValues();
9.8 - values.setFamily(name);
9.9 - values.setSize(pointSize); // expects the float value.
9.10 + AttributeValues valuesTmp = new AttributeValues();
9.11 + valuesTmp.setFamily(name);
9.12 + valuesTmp.setSize(pointSize); // expects the float value.
9.13
9.14 if ((style & BOLD) != 0) {
9.15 - values.setWeight(2); // WEIGHT_BOLD
9.16 + valuesTmp.setWeight(2); // WEIGHT_BOLD
9.17 }
9.18
9.19 if ((style & ITALIC) != 0) {
9.20 - values.setPosture(.2f); // POSTURE_OBLIQUE
9.21 + valuesTmp.setPosture(.2f); // POSTURE_OBLIQUE
9.22 }
9.23 - values.defineAll(PRIMARY_MASK); // for streaming compatibility
9.24 + valuesTmp.defineAll(PRIMARY_MASK); // for streaming compatibility
9.25 + values = valuesTmp;
9.26 }
9.27
9.28 return values;
10.1 --- a/src/share/classes/java/awt/GraphicsEnvironment.java Thu Jun 25 12:10:01 2009 -0700
10.2 +++ b/src/share/classes/java/awt/GraphicsEnvironment.java Mon Jun 29 14:42:22 2009 -0700
10.3 @@ -79,8 +79,9 @@
10.4
10.5 try {
10.6 // long t0 = System.currentTimeMillis();
10.7 - localEnv =
10.8 - (GraphicsEnvironment) Class.forName(nm).newInstance();
10.9 + ClassLoader cl = ClassLoader.getSystemClassLoader();
10.10 + Class geCls = Class.forName(nm, true, cl);
10.11 + localEnv = (GraphicsEnvironment)geCls.newInstance();
10.12 // long t1 = System.currentTimeMillis();
10.13 // System.out.println("GE creation took " + (t1-t0)+ "ms.");
10.14 if (isHeadless()) {
11.1 --- a/src/share/classes/java/awt/color/ICC_Profile.java Thu Jun 25 12:10:01 2009 -0700
11.2 +++ b/src/share/classes/java/awt/color/ICC_Profile.java Mon Jun 29 14:42:22 2009 -0700
11.3 @@ -863,11 +863,16 @@
11.4 case ColorSpace.CS_PYCC:
11.5 synchronized(ICC_Profile.class) {
11.6 if (PYCCprofile == null) {
11.7 - ProfileDeferralInfo pInfo =
11.8 - new ProfileDeferralInfo("PYCC.pf",
11.9 - ColorSpace.TYPE_3CLR, 3,
11.10 - CLASS_DISPLAY);
11.11 - PYCCprofile = getDeferredInstance(pInfo);
11.12 + if (getProfileFile("PYCC.pf") != null) {
11.13 + ProfileDeferralInfo pInfo =
11.14 + new ProfileDeferralInfo("PYCC.pf",
11.15 + ColorSpace.TYPE_3CLR, 3,
11.16 + CLASS_DISPLAY);
11.17 + PYCCprofile = getDeferredInstance(pInfo);
11.18 + } else {
11.19 + throw new IllegalArgumentException(
11.20 + "Can't load standard profile: PYCC.pf");
11.21 + }
11.22 }
11.23 thisProfile = PYCCprofile;
11.24 }
11.25 @@ -1783,17 +1788,33 @@
11.26 return (FileInputStream)java.security.AccessController.doPrivileged(
11.27 new java.security.PrivilegedAction() {
11.28 public Object run() {
11.29 - return privilegedOpenProfile(fileName);
11.30 + File f = privilegedGetProfileFile(fileName);
11.31 + if (f != null) {
11.32 + try {
11.33 + return new FileInputStream(f);
11.34 + } catch (FileNotFoundException e) {
11.35 + }
11.36 + }
11.37 + return null;
11.38 + }
11.39 + });
11.40 + }
11.41 +
11.42 + private static File getProfileFile(final String fileName) {
11.43 + return (File)java.security.AccessController.doPrivileged(
11.44 + new java.security.PrivilegedAction() {
11.45 + public Object run() {
11.46 + return privilegedGetProfileFile(fileName);
11.47 }
11.48 });
11.49 }
11.50
11.51 /*
11.52 - * this version is called from doPrivileged in privilegedOpenProfile.
11.53 - * the whole method is privileged!
11.54 + * this version is called from doPrivileged in openProfile
11.55 + * or getProfileFile, so the whole method is privileged!
11.56 */
11.57 - private static FileInputStream privilegedOpenProfile(String fileName) {
11.58 - FileInputStream fis = null;
11.59 +
11.60 + private static File privilegedGetProfileFile(String fileName) {
11.61 String path, dir, fullPath;
11.62
11.63 File f = new File(fileName); /* try absolute file name */
11.64 @@ -1830,12 +1851,9 @@
11.65 }
11.66
11.67 if (f.isFile()) {
11.68 - try {
11.69 - fis = new FileInputStream(f);
11.70 - } catch (FileNotFoundException e) {
11.71 - }
11.72 + return f;
11.73 }
11.74 - return fis;
11.75 + return null;
11.76 }
11.77
11.78
12.1 --- a/src/share/classes/javax/imageio/ImageIO.java Thu Jun 25 12:10:01 2009 -0700
12.2 +++ b/src/share/classes/javax/imageio/ImageIO.java Mon Jun 29 14:42:22 2009 -0700
12.3 @@ -28,6 +28,7 @@
12.4 import java.awt.image.BufferedImage;
12.5 import java.awt.image.RenderedImage;
12.6 import java.io.File;
12.7 +import java.io.FilePermission;
12.8 import java.io.InputStream;
12.9 import java.io.IOException;
12.10 import java.io.OutputStream;
12.11 @@ -195,13 +196,22 @@
12.12 } else {
12.13 cachepath = getTempDir();
12.14
12.15 - if (cachepath == null) {
12.16 + if (cachepath == null || cachepath.isEmpty()) {
12.17 getCacheInfo().setHasPermission(Boolean.FALSE);
12.18 return false;
12.19 }
12.20 }
12.21
12.22 - security.checkWrite(cachepath);
12.23 + // we have to check whether we can read, write,
12.24 + // and delete cache files.
12.25 + // So, compose cache file path and check it.
12.26 + String filepath = cachepath;
12.27 + if (!filepath.endsWith(File.separator)) {
12.28 + filepath += File.separator;
12.29 + }
12.30 + filepath += "*";
12.31 +
12.32 + security.checkPermission(new FilePermission(filepath, "read, write, delete"));
12.33 }
12.34 } catch (SecurityException e) {
12.35 getCacheInfo().setHasPermission(Boolean.FALSE);
13.1 --- a/src/share/classes/sun/font/TrueTypeFont.java Thu Jun 25 12:10:01 2009 -0700
13.2 +++ b/src/share/classes/sun/font/TrueTypeFont.java Mon Jun 29 14:42:22 2009 -0700
13.3 @@ -160,6 +160,13 @@
13.4 private boolean supportsJA;
13.5 private boolean supportsCJK;
13.6
13.7 + /* These are for faster access to the name of the font as
13.8 + * typically exposed via API to applications.
13.9 + */
13.10 + private Locale nameLocale;
13.11 + private String localeFamilyName;
13.12 + private String localeFullName;
13.13 +
13.14 /**
13.15 * - does basic verification of the file
13.16 * - reads the header table for this font (within a collection)
13.17 @@ -1092,6 +1099,10 @@
13.18 * greater than 32767, so read and store those as ints
13.19 */
13.20 int stringPtr = sbuffer.get() & 0xffff;
13.21 +
13.22 + nameLocale = sun.awt.SunToolkit.getStartupLocale();
13.23 + short nameLocaleID = FontManager.getLCIDFromLocale(nameLocale);
13.24 +
13.25 for (int i=0; i<numRecords; i++) {
13.26 short platformID = sbuffer.get();
13.27 if (platformID != MS_PLATFORM_ID) {
13.28 @@ -1103,15 +1114,24 @@
13.29 short nameID = sbuffer.get();
13.30 int nameLen = ((int) sbuffer.get()) & 0xffff;
13.31 int namePtr = (((int) sbuffer.get()) & 0xffff) + stringPtr;
13.32 -
13.33 + String tmpName = null;
13.34 switch (nameID) {
13.35
13.36 case FAMILY_NAME_ID:
13.37
13.38 - if (familyName == null || langID == ENGLISH_LOCALE_ID) {
13.39 + if (familyName == null || langID == ENGLISH_LOCALE_ID ||
13.40 + langID == nameLocaleID)
13.41 + {
13.42 buffer.position(namePtr);
13.43 buffer.get(name, 0, nameLen);
13.44 - familyName = makeString(name, nameLen, encodingID);
13.45 + tmpName = makeString(name, nameLen, encodingID);
13.46 +
13.47 + if (familyName == null || langID == ENGLISH_LOCALE_ID){
13.48 + familyName = tmpName;
13.49 + }
13.50 + if (langID == nameLocaleID) {
13.51 + localeFamilyName = tmpName;
13.52 + }
13.53 }
13.54 /*
13.55 for (int ii=0;ii<nameLen;ii++) {
13.56 @@ -1129,15 +1149,29 @@
13.57
13.58 case FULL_NAME_ID:
13.59
13.60 - if (fullName == null || langID == ENGLISH_LOCALE_ID) {
13.61 + if (fullName == null || langID == ENGLISH_LOCALE_ID ||
13.62 + langID == nameLocaleID)
13.63 + {
13.64 buffer.position(namePtr);
13.65 buffer.get(name, 0, nameLen);
13.66 - fullName = makeString(name, nameLen, encodingID);
13.67 + tmpName = makeString(name, nameLen, encodingID);
13.68 +
13.69 + if (fullName == null || langID == ENGLISH_LOCALE_ID) {
13.70 + fullName = tmpName;
13.71 + }
13.72 + if (langID == nameLocaleID) {
13.73 + localeFullName = tmpName;
13.74 + }
13.75 }
13.76 break;
13.77 -
13.78 }
13.79 }
13.80 + if (localeFamilyName == null) {
13.81 + localeFamilyName = familyName;
13.82 + }
13.83 + if (localeFullName == null) {
13.84 + localeFullName = fullName;
13.85 + }
13.86 }
13.87 }
13.88
13.89 @@ -1220,6 +1254,8 @@
13.90 public String getFontName(Locale locale) {
13.91 if (locale == null) {
13.92 return fullName;
13.93 + } else if (locale.equals(nameLocale) && localeFullName != null) {
13.94 + return localeFullName;
13.95 } else {
13.96 short localeID = FontManager.getLCIDFromLocale(locale);
13.97 String name = lookupName(localeID, FULL_NAME_ID);
13.98 @@ -1234,11 +1270,13 @@
13.99 public String getFamilyName(Locale locale) {
13.100 if (locale == null) {
13.101 return familyName;
13.102 + } else if (locale.equals(nameLocale) && localeFamilyName != null) {
13.103 + return localeFamilyName;
13.104 } else {
13.105 short localeID = FontManager.getLCIDFromLocale(locale);
13.106 String name = lookupName(localeID, FAMILY_NAME_ID);
13.107 if (name == null) {
13.108 - return familyName;
13.109 + return familyName;
13.110 } else {
13.111 return name;
13.112 }
14.1 --- a/src/share/classes/sun/java2d/pisces/PiscesCache.java Thu Jun 25 12:10:01 2009 -0700
14.2 +++ b/src/share/classes/sun/java2d/pisces/PiscesCache.java Mon Jun 29 14:42:22 2009 -0700
14.3 @@ -96,7 +96,7 @@
14.4 bboxX1 = x1+1;
14.5 } else {
14.6 if (bboxX0 > x0) bboxX0 = x0;
14.7 - if (bboxX1 < x1) bboxX1 = x1;
14.8 + if (bboxX1 < x1 + 1) bboxX1 = x1 + 1;
14.9 while (bboxY1++ < y) {
14.10 reallocRowInfo(alphaRows+1);
14.11 minTouched[alphaRows] = 0;
15.1 --- a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Thu Jun 25 12:10:01 2009 -0700
15.2 +++ b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Mon Jun 29 14:42:22 2009 -0700
15.3 @@ -1783,7 +1783,7 @@
15.4
15.5
15.6 struct jpeg_source_mgr *src;
15.7 - JSAMPROW scanLinePtr;
15.8 + JSAMPROW scanLinePtr = NULL;
15.9 jint bands[MAX_BANDS];
15.10 int i, j;
15.11 jint *body;
15.12 @@ -1819,7 +1819,7 @@
15.13
15.14 cinfo = (j_decompress_ptr) data->jpegObj;
15.15
15.16 - if ((numBands < 1) || (numBands > cinfo->num_components) ||
15.17 + if ((numBands < 1) ||
15.18 (sourceXStart < 0) || (sourceXStart >= (jint)cinfo->image_width) ||
15.19 (sourceYStart < 0) || (sourceYStart >= (jint)cinfo->image_height) ||
15.20 (sourceWidth < 1) || (sourceWidth > (jint)cinfo->image_width) ||
15.21 @@ -1877,16 +1877,6 @@
15.22 return data->abortFlag; // We already threw an out of memory exception
15.23 }
15.24
15.25 - // Allocate a 1-scanline buffer
15.26 - scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->num_components);
15.27 - if (scanLinePtr == NULL) {
15.28 - RELEASE_ARRAYS(env, data, src->next_input_byte);
15.29 - JNU_ThrowByName( env,
15.30 - "java/lang/OutOfMemoryError",
15.31 - "Reading JPEG Stream");
15.32 - return data->abortFlag;
15.33 - }
15.34 -
15.35 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */
15.36 jerr = (sun_jpeg_error_ptr) cinfo->err;
15.37
15.38 @@ -1900,7 +1890,10 @@
15.39 buffer);
15.40 JNU_ThrowByName(env, "javax/imageio/IIOException", buffer);
15.41 }
15.42 - free(scanLinePtr);
15.43 + if (scanLinePtr != NULL) {
15.44 + free(scanLinePtr);
15.45 + scanLinePtr = NULL;
15.46 + }
15.47 return data->abortFlag;
15.48 }
15.49
15.50 @@ -1938,6 +1931,23 @@
15.51
15.52 jpeg_start_decompress(cinfo);
15.53
15.54 + if (numBands != cinfo->output_components) {
15.55 + JNU_ThrowByName(env, "javax/imageio/IIOException",
15.56 + "Invalid argument to native readImage");
15.57 + return data->abortFlag;
15.58 + }
15.59 +
15.60 +
15.61 + // Allocate a 1-scanline buffer
15.62 + scanLinePtr = (JSAMPROW)malloc(cinfo->image_width*cinfo->output_components);
15.63 + if (scanLinePtr == NULL) {
15.64 + RELEASE_ARRAYS(env, data, src->next_input_byte);
15.65 + JNU_ThrowByName( env,
15.66 + "java/lang/OutOfMemoryError",
15.67 + "Reading JPEG Stream");
15.68 + return data->abortFlag;
15.69 + }
15.70 +
15.71 // loop over progressive passes
15.72 done = FALSE;
15.73 while (!done) {
15.74 @@ -1965,9 +1975,9 @@
15.75
15.76 scanlineLimit = sourceYStart+sourceHeight;
15.77 pixelLimit = scanLinePtr
15.78 - +(sourceXStart+sourceWidth)*cinfo->num_components;
15.79 -
15.80 - pixelStride = stepX*cinfo->num_components;
15.81 + +(sourceXStart+sourceWidth)*cinfo->output_components;
15.82 +
15.83 + pixelStride = stepX*cinfo->output_components;
15.84 targetLine = 0;
15.85
15.86 while ((data->abortFlag == JNI_FALSE)
15.87 @@ -1982,12 +1992,12 @@
15.88 // Optimization: The component bands are ordered sequentially,
15.89 // so we can simply use memcpy() to copy the intermediate
15.90 // scanline buffer into the raster.
15.91 - in = scanLinePtr + (sourceXStart * cinfo->num_components);
15.92 + in = scanLinePtr + (sourceXStart * cinfo->output_components);
15.93 if (pixelLimit > in) {
15.94 memcpy(out, in, pixelLimit - in);
15.95 }
15.96 } else {
15.97 - for (in = scanLinePtr+sourceXStart*cinfo->num_components;
15.98 + for (in = scanLinePtr+sourceXStart*cinfo->output_components;
15.99 in < pixelLimit;
15.100 in += pixelStride) {
15.101 for (i = 0; i < numBands; i++) {
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/test/javax/imageio/CachePremissionsTest/CachePermissionsTest.java Mon Jun 29 14:42:22 2009 -0700
16.3 @@ -0,0 +1,120 @@
16.4 +/*
16.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
16.7 + *
16.8 + * This code is free software; you can redistribute it and/or modify it
16.9 + * under the terms of the GNU General Public License version 2 only, as
16.10 + * published by the Free Software Foundation.
16.11 + *
16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16.15 + * version 2 for more details (a copy is included in the LICENSE file that
16.16 + * accompanied this code).
16.17 + *
16.18 + * You should have received a copy of the GNU General Public License version
16.19 + * 2 along with this work; if not, write to the Free Software Foundation,
16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
16.21 + *
16.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
16.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
16.24 + * have any questions.
16.25 + */
16.26 +
16.27 +/**
16.28 + * @test
16.29 + * @bug 6684104
16.30 + * @summary Test verifies that ImageIO checks all permissions required for
16.31 + * the file cache usage:
16.32 + *
16.33 + * no policy file: No security restrictions.
16.34 + * Expected result: ImageIO creates file-cached stream.
16.35 + *
16.36 + * w.policy: the case when we have read and write permissions
16.37 + * for java.io.temp directory but have only write permission
16.38 + * for a temp file.
16.39 + * Expected result: ImageIO create a memory-cached stream
16.40 + * image output stream.
16.41 + *
16.42 + * rw.policy: the case when we have read and write permissions
16.43 + * for java.io.temp directory but have only read and write
16.44 + * permission for a temp cache file.
16.45 + * Expected result: ImageIO creates a memory-cached stream
16.46 + * because temporary cache file can not be deleted.
16.47 + *
16.48 + * rwd.policy: the case when we have read and write permissions
16.49 + * for java.io.temp directory and have all required permissions
16.50 + * (read, write, and delete) for a temporary cache file.
16.51 + * Expected result: ImageIO creates file-cached stream.
16.52 + *
16.53 + * -Djava.security.debug=access can be used to verify file permissions.
16.54 + *
16.55 + * @run main CachePermissionsTest true
16.56 + * @run main/othervm/policy=w.policy CachePermissionsTest false
16.57 + * @run main/othervm/policy=rw.policy CachePermissionsTest false
16.58 + * @run main/othervm/policy=rwd.policy CachePermissionsTest true
16.59 + */
16.60 +
16.61 +import java.io.File;
16.62 +import java.io.IOException;
16.63 +import java.io.ByteArrayOutputStream;
16.64 +import javax.imageio.stream.ImageOutputStream;
16.65 +
16.66 +import javax.imageio.ImageIO;
16.67 +
16.68 +
16.69 +public class CachePermissionsTest {
16.70 + public static void main(String[] args) {
16.71 + boolean isFileCacheExpected =
16.72 + Boolean.valueOf(args[0]).booleanValue();
16.73 + System.out.println("Is file cache expected: " + isFileCacheExpected);
16.74 +
16.75 + ImageIO.setUseCache(true);
16.76 +
16.77 + System.out.println("java.io.tmpdir is " + System.getProperty("java.io.tmpdir"));
16.78 +
16.79 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
16.80 +
16.81 + try {
16.82 + ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
16.83 +
16.84 + boolean isFileCache = ios.isCachedFile();
16.85 + System.out.println("Is file cache used: " + isFileCache);
16.86 +
16.87 + if (isFileCache !=isFileCacheExpected) {
16.88 + System.out.println("WARNING: file chace usage is not as expected!");
16.89 + }
16.90 +
16.91 + System.out.println("Verify data writing...");
16.92 + for (int i = 0; i < 8192; i++) {
16.93 + ios.writeInt(i);
16.94 + }
16.95 +
16.96 + System.out.println("Verify data reading...");
16.97 + ios.seek(0L);
16.98 +
16.99 + for (int i = 0; i < 8192; i++) {
16.100 + int j = ios.readInt();
16.101 + if (i != j) {
16.102 + throw new RuntimeException("Wrong data in the stream " + j + " instead of " + i);
16.103 + }
16.104 + }
16.105 +
16.106 + System.out.println("Verify stream closing...");
16.107 + ios.close();
16.108 + } catch (IOException e) {
16.109 + /*
16.110 + * Something went wrong?
16.111 + */
16.112 + throw new RuntimeException("Test FAILED.", e);
16.113 + } catch (SecurityException e) {
16.114 + /*
16.115 + * We do not expect security execptions here:
16.116 + * we there are any security restrition, ImageIO
16.117 + * should swith to memory-cached streams, instead
16.118 + * of using file cache.
16.119 + */
16.120 + throw new RuntimeException("Test FAILED.", e);
16.121 + }
16.122 + }
16.123 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/test/javax/imageio/CachePremissionsTest/rw.policy Mon Jun 29 14:42:22 2009 -0700
17.3 @@ -0,0 +1,5 @@
17.4 +grant {
17.5 + permission java.util.PropertyPermission "test.classes", "read";
17.6 + permission java.util.PropertyPermission "java.io.tmpdir", "read";
17.7 + permission java.io.FilePermission "${java.io.tmpdir}${/}*", "read, write";
17.8 +};
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/test/javax/imageio/CachePremissionsTest/rwd.policy Mon Jun 29 14:42:22 2009 -0700
18.3 @@ -0,0 +1,5 @@
18.4 +grant {
18.5 + permission java.util.PropertyPermission "test.classes", "read";
18.6 + permission java.util.PropertyPermission "java.io.tmpdir", "read";
18.7 + permission java.io.FilePermission "${java.io.tmpdir}${/}*", "read, write, delete";
18.8 +};
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/test/javax/imageio/CachePremissionsTest/w.policy Mon Jun 29 14:42:22 2009 -0700
19.3 @@ -0,0 +1,5 @@
19.4 +grant {
19.5 + permission java.util.PropertyPermission "test.classes", "read";
19.6 + permission java.util.PropertyPermission "java.io.tmpdir", "read";
19.7 + permission java.io.FilePermission "${java.io.tmpdir}${/}*", "write";
19.8 +};
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/test/javax/imageio/plugins/bmp/TopDownTest.java Mon Jun 29 14:42:22 2009 -0700
20.3 @@ -0,0 +1,142 @@
20.4 +/*
20.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
20.7 + *
20.8 + * This code is free software; you can redistribute it and/or modify it
20.9 + * under the terms of the GNU General Public License version 2 only, as
20.10 + * published by the Free Software Foundation.
20.11 + *
20.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
20.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20.15 + * version 2 for more details (a copy is included in the LICENSE file that
20.16 + * accompanied this code).
20.17 + *
20.18 + * You should have received a copy of the GNU General Public License version
20.19 + * 2 along with this work; if not, write to the Free Software Foundation,
20.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20.21 + *
20.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
20.24 + * have any questions.
20.25 + */
20.26 +
20.27 +/**
20.28 + * @test
20.29 + * @bug 6296893
20.30 + * @summary Test verifies that the isTopDown flag does not cause
20.31 + * a writing of bmp image in wrong scanline layout.
20.32 + * @run main TopDownTest
20.33 + */
20.34 +
20.35 +import java.awt.Color;
20.36 +import java.awt.Graphics;
20.37 +import java.awt.image.BufferedImage;
20.38 +
20.39 +import java.awt.image.IndexColorModel;
20.40 +import java.io.File;
20.41 +import java.io.IOException;
20.42 +import javax.imageio.IIOImage;
20.43 +import javax.imageio.ImageIO;
20.44 +import javax.imageio.ImageWriteParam;
20.45 +import javax.imageio.ImageWriter;
20.46 +import javax.imageio.plugins.bmp.BMPImageWriteParam;
20.47 +import javax.imageio.stream.ImageOutputStream;
20.48 +import static java.awt.image.BufferedImage.TYPE_INT_RGB;
20.49 +import static java.awt.image.BufferedImage.TYPE_BYTE_INDEXED;
20.50 +
20.51 +public class TopDownTest {
20.52 +
20.53 + public static void main(String[] args) throws IOException {
20.54 + BufferedImage src = createTestImage(24);
20.55 +
20.56 + writeWithCompression(src, "BI_BITFIELDS");
20.57 +
20.58 + writeWithCompression(src, "BI_RGB");
20.59 +
20.60 + src = createTestImage(8);
20.61 + writeWithCompression(src, "BI_RLE8");
20.62 +
20.63 + src = createTestImage(4);
20.64 + writeWithCompression(src, "BI_RLE4");
20.65 +
20.66 + }
20.67 +
20.68 + private static void writeWithCompression(BufferedImage src,
20.69 + String compression) throws IOException
20.70 + {
20.71 + System.out.println("Compression: " + compression);
20.72 + ImageWriter writer = ImageIO.getImageWritersByFormatName("BMP").next();
20.73 + if (writer == null) {
20.74 + throw new RuntimeException("Test failed: no bmp writer available");
20.75 + }
20.76 + File fout = File.createTempFile(compression + "_", ".bmp",
20.77 + new File("."));
20.78 +
20.79 + ImageOutputStream ios = ImageIO.createImageOutputStream(fout);
20.80 + writer.setOutput(ios);
20.81 +
20.82 + BMPImageWriteParam param = (BMPImageWriteParam)
20.83 + writer.getDefaultWriteParam();
20.84 + param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
20.85 + param.setCompressionType(compression);
20.86 + param.setTopDown(true);
20.87 + writer.write(null, new IIOImage(src, null, null), param);
20.88 + writer.dispose();
20.89 + ios.flush();
20.90 + ios.close();
20.91 +
20.92 + BufferedImage dst = ImageIO.read(fout);
20.93 +
20.94 + verify(dst);
20.95 + }
20.96 +
20.97 + private static void verify(BufferedImage dst) {
20.98 + int top_rgb = dst.getRGB(50, 25);
20.99 + System.out.printf("top_rgb: %x\n", top_rgb);
20.100 + int bot_rgb = dst.getRGB(50, 75);
20.101 + System.out.printf("bot_rgb: %x\n", bot_rgb);
20.102 +
20.103 + // expect to see blue color on the top of image
20.104 + if (top_rgb != 0xff0000ff) {
20.105 + throw new RuntimeException("Invaid top color: " +
20.106 + Integer.toHexString(bot_rgb));
20.107 + }
20.108 + if (bot_rgb != 0xffff0000) {
20.109 + throw new RuntimeException("Invalid bottom color: " +
20.110 + Integer.toHexString(bot_rgb));
20.111 + }
20.112 + }
20.113 +
20.114 + private static BufferedImage createTestImage(int bpp) {
20.115 +
20.116 + BufferedImage img = null;
20.117 + switch (bpp) {
20.118 + case 8:
20.119 + img = new BufferedImage(100, 100, TYPE_BYTE_INDEXED);
20.120 + break;
20.121 + case 4: {
20.122 + byte[] r = new byte[16];
20.123 + byte[] g = new byte[16];
20.124 + byte[] b = new byte[16];
20.125 +
20.126 + r[1] = (byte)0xff;
20.127 + b[0] = (byte)0xff;
20.128 +
20.129 + IndexColorModel icm = new IndexColorModel(4, 16, r, g, b);
20.130 + img = new BufferedImage(100, 100, TYPE_BYTE_INDEXED, icm);
20.131 + }
20.132 + break;
20.133 + case 24:
20.134 + default:
20.135 + img = new BufferedImage(100, 100, TYPE_INT_RGB);
20.136 + }
20.137 + Graphics g = img.createGraphics();
20.138 + g.setColor(Color.blue);
20.139 + g.fillRect(0, 0, 100, 50);
20.140 + g.setColor(Color.red);
20.141 + g.fillRect(0, 50, 100, 50);
20.142 + g.dispose();
20.143 + return img;
20.144 + }
20.145 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/test/javax/imageio/plugins/jpeg/ReadAsGrayTest.java Mon Jun 29 14:42:22 2009 -0700
21.3 @@ -0,0 +1,179 @@
21.4 +/*
21.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
21.7 + *
21.8 + * This code is free software; you can redistribute it and/or modify it
21.9 + * under the terms of the GNU General Public License version 2 only, as
21.10 + * published by the Free Software Foundation.
21.11 + *
21.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
21.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21.15 + * version 2 for more details (a copy is included in the LICENSE file that
21.16 + * accompanied this code).
21.17 + *
21.18 + * You should have received a copy of the GNU General Public License version
21.19 + * 2 along with this work; if not, write to the Free Software Foundation,
21.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21.21 + *
21.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
21.24 + * have any questions.
21.25 + */
21.26 +
21.27 +/**
21.28 + * @test
21.29 + * @bug 4893408
21.30 + *
21.31 + * @summary Test verifies that Image I/O jpeg reader correctly handles
21.32 + * destination types if number of color components in destination
21.33 + * differs from number of color components in the jpeg image.
21.34 + * Particularly, it verifies reading YCbCr image as a grayscaled
21.35 + * and reading grayscaled jpeg as a RGB.
21.36 + *
21.37 + * @run main ReadAsGrayTest
21.38 + */
21.39 +
21.40 +import java.awt.Color;
21.41 +import java.awt.Graphics2D;
21.42 +import java.awt.color.ColorSpace;
21.43 +import java.awt.image.BufferedImage;
21.44 +import java.io.File;
21.45 +import java.io.IOException;
21.46 +import java.util.Iterator;
21.47 +import javax.imageio.ImageIO;
21.48 +import javax.imageio.ImageReadParam;
21.49 +import javax.imageio.ImageReader;
21.50 +import javax.imageio.ImageTypeSpecifier;
21.51 +import javax.imageio.stream.ImageInputStream;
21.52 +import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
21.53 +import static java.awt.image.BufferedImage.TYPE_BYTE_GRAY;
21.54 +import static java.awt.color.ColorSpace.TYPE_GRAY;
21.55 +import static java.awt.color.ColorSpace.CS_sRGB;
21.56 +
21.57 +public class ReadAsGrayTest {
21.58 + static Color[] colors = new Color[] {
21.59 + Color.white, Color.red, Color.green,
21.60 + Color.blue, Color.black };
21.61 +
21.62 + static final int dx = 50;
21.63 + static final int h = 100;
21.64 +
21.65 + static ColorSpace sRGB = ColorSpace.getInstance(CS_sRGB);
21.66 +
21.67 +
21.68 + public static void main(String[] args) throws IOException {
21.69 + System.out.println("Type TYPE_BYTE_GRAY");
21.70 + doTest(TYPE_BYTE_GRAY);
21.71 +
21.72 + System.out.println("Type TYPE_3BYTE_BGR");
21.73 + doTest(TYPE_3BYTE_BGR);
21.74 +
21.75 + System.out.println("Test PASSED.");
21.76 + }
21.77 +
21.78 + private static void doTest(int type) throws IOException {
21.79 + BufferedImage src = createTestImage(type);
21.80 +
21.81 + File f = new File("test.jpg");
21.82 +
21.83 + if (!ImageIO.write(src, "jpg", f)) {
21.84 + throw new RuntimeException("Failed to write test image.");
21.85 + }
21.86 +
21.87 + ImageInputStream iis = ImageIO.createImageInputStream(f);
21.88 + ImageReader reader = ImageIO.getImageReaders(iis).next();
21.89 + reader.setInput(iis);
21.90 +
21.91 + Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
21.92 + ImageTypeSpecifier srgb = null;
21.93 + ImageTypeSpecifier gray = null;
21.94 + // look for gray and srgb types
21.95 + while ((srgb == null || gray == null) && types.hasNext()) {
21.96 + ImageTypeSpecifier t = types.next();
21.97 + if (t.getColorModel().getColorSpace().getType() == TYPE_GRAY) {
21.98 + gray = t;
21.99 + }
21.100 + if (t.getColorModel().getColorSpace() == sRGB) {
21.101 + srgb = t;
21.102 + }
21.103 + }
21.104 + if (gray == null) {
21.105 + throw new RuntimeException("No gray type available.");
21.106 + }
21.107 + if (srgb == null) {
21.108 + throw new RuntimeException("No srgb type available.");
21.109 + }
21.110 +
21.111 + System.out.println("Read as GRAY...");
21.112 + testType(reader, gray, src);
21.113 +
21.114 + System.out.println("Read as sRGB...");
21.115 + testType(reader, srgb, src);
21.116 + }
21.117 +
21.118 + private static void testType(ImageReader reader,
21.119 + ImageTypeSpecifier t,
21.120 + BufferedImage src)
21.121 + throws IOException
21.122 + {
21.123 + ImageReadParam p = reader.getDefaultReadParam();
21.124 + p.setDestinationType(t);
21.125 + BufferedImage dst = reader.read(0, p);
21.126 +
21.127 + verify(src, dst, t);
21.128 + }
21.129 +
21.130 + private static void verify(BufferedImage src,
21.131 + BufferedImage dst,
21.132 + ImageTypeSpecifier type)
21.133 + {
21.134 + BufferedImage test =
21.135 + type.createBufferedImage(src.getWidth(), src.getHeight());
21.136 + Graphics2D g = test.createGraphics();
21.137 + g.drawImage(src, 0, 0, null);
21.138 + g.dispose();
21.139 +
21.140 + for (int i = 0; i < colors.length; i++) {
21.141 + int x = i * dx + dx / 2;
21.142 + int y = h / 2;
21.143 +
21.144 + Color c_test = new Color(test.getRGB(x, y));
21.145 + Color c_dst = new Color(dst.getRGB(x, y));
21.146 +
21.147 + if (!compareWithTolerance(c_test, c_dst, 0.01f)) {
21.148 + String msg = String.format("Invalid color: %x instead of %x",
21.149 + c_dst.getRGB(), c_test.getRGB());
21.150 + throw new RuntimeException("Test failed: " + msg);
21.151 + }
21.152 + }
21.153 + System.out.println("Verified.");
21.154 + }
21.155 +
21.156 + private static boolean compareWithTolerance(Color a, Color b, float delta) {
21.157 + float[] a_rgb = new float[3];
21.158 + a_rgb = a.getRGBColorComponents(a_rgb);
21.159 + float[] b_rgb = new float[3];
21.160 + b_rgb = b.getRGBColorComponents(b_rgb);
21.161 +
21.162 + for (int i = 0; i < 3; i++) {
21.163 + if (Math.abs(a_rgb[i] - b_rgb[i]) > delta) {
21.164 + return false;
21.165 + }
21.166 + }
21.167 + return true;
21.168 + }
21.169 +
21.170 + private static BufferedImage createTestImage(int type) {
21.171 + BufferedImage img = new BufferedImage(dx * colors.length, h, type);
21.172 +
21.173 + Graphics2D g = img.createGraphics();
21.174 + for (int i = 0; i < colors.length; i++) {
21.175 + g.setColor(colors[i]);
21.176 + g.fillRect(i * dx, 0, dx, h);
21.177 + }
21.178 + g.dispose();
21.179 +
21.180 + return img;
21.181 + }
21.182 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/test/javax/imageio/plugins/wbmp/CanDecodeTest.java Mon Jun 29 14:42:22 2009 -0700
22.3 @@ -0,0 +1,131 @@
22.4 +/*
22.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
22.7 + *
22.8 + * This code is free software; you can redistribute it and/or modify it
22.9 + * under the terms of the GNU General Public License version 2 only, as
22.10 + * published by the Free Software Foundation.
22.11 + *
22.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
22.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22.15 + * version 2 for more details (a copy is included in the LICENSE file that
22.16 + * accompanied this code).
22.17 + *
22.18 + * You should have received a copy of the GNU General Public License version
22.19 + * 2 along with this work; if not, write to the Free Software Foundation,
22.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22.21 + *
22.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
22.24 + * have any questions.
22.25 + */
22.26 +
22.27 +/**
22.28 + * @test
22.29 + * @bug 5101862
22.30 + * @summary Test verifies that SPI of WBMP image reader
22.31 + * does not claims to be able to decode QT movies,
22.32 + * tga images, or ico files.
22.33 + * @run main CanDecodeTest
22.34 + */
22.35 +
22.36 +import java.io.ByteArrayInputStream;
22.37 +import java.io.File;
22.38 +import java.io.FileOutputStream;
22.39 +import java.io.IOException;
22.40 +import java.io.InputStream;
22.41 +import java.util.Arrays;
22.42 +import java.util.Vector;
22.43 +import javax.imageio.ImageIO;
22.44 +import javax.imageio.ImageReader;
22.45 +import javax.imageio.spi.ImageReaderSpi;
22.46 +import javax.imageio.stream.ImageInputStream;
22.47 +
22.48 +public class CanDecodeTest {
22.49 +
22.50 + public static void main(String[] args) throws IOException {
22.51 + ImageReader r =
22.52 + ImageIO.getImageReadersByFormatName("WBMP").next();
22.53 + ImageReaderSpi spi = r.getOriginatingProvider();
22.54 +
22.55 + Vector<TestCase> tests = getTestCases();
22.56 + for (TestCase t : tests) {
22.57 + t.doTest(spi);
22.58 + }
22.59 + System.out.println("Test passed.");
22.60 + }
22.61 +
22.62 + private static Vector<TestCase> getTestCases() {
22.63 + Vector<TestCase> v = new Vector<TestCase>(4);
22.64 + v.add(new TestCase("wbmp", new byte[]{(byte) 0x00, (byte) 0x00,
22.65 + (byte) 0x60, (byte) 0x14}, 244, true));
22.66 + v.add(new TestCase("mov", new byte[]{(byte) 0x00, (byte) 0x00,
22.67 + (byte) 0x07, (byte) 0xb5, (byte) 0x6d}, 82397, false));
22.68 + v.add(new TestCase("tga", new byte[]{(byte) 0x00, (byte) 0x00,
22.69 + (byte) 0x0a, (byte) 0x00}, 39693, false));
22.70 + v.add(new TestCase("ico", new byte[]{(byte) 0x00, (byte) 0x00,
22.71 + (byte) 0x01, (byte) 0x00}, 1078, false));
22.72 + return v;
22.73 + }
22.74 +
22.75 + private static class TestCase {
22.76 +
22.77 + private String title;
22.78 + private byte[] header;
22.79 + private int dataLength;
22.80 + private boolean canDecode;
22.81 +
22.82 + public TestCase(String title, byte[] header,
22.83 + int dataLength, boolean canDecode) {
22.84 + this.title = title;
22.85 + this.dataLength = dataLength;
22.86 + this.header = header.clone();
22.87 + this.canDecode = canDecode;
22.88 +
22.89 + }
22.90 +
22.91 + public void doTest(ImageReaderSpi spi) throws IOException {
22.92 + System.out.println("Test for " + title +
22.93 + (canDecode ? " (can decode)" : " (can't decode)"));
22.94 + System.out.print("As a stream...");
22.95 + ImageInputStream iis =
22.96 + ImageIO.createImageInputStream(getDataStream());
22.97 +
22.98 + if (spi.canDecodeInput(iis) != canDecode) {
22.99 + throw new RuntimeException("Test failed: wrong decideion " +
22.100 + "for stream data");
22.101 + }
22.102 + System.out.println("OK");
22.103 +
22.104 + System.out.print("As a file...");
22.105 + iis = ImageIO.createImageInputStream(getDataFile());
22.106 + if (spi.canDecodeInput(iis) != canDecode) {
22.107 + throw new RuntimeException("Test failed: wrong decideion " +
22.108 + "for file data");
22.109 + }
22.110 + System.out.println("OK");
22.111 + }
22.112 +
22.113 + private byte[] getData() {
22.114 + byte[] data = new byte[dataLength];
22.115 + Arrays.fill(data, (byte) 0);
22.116 + System.arraycopy(header, 0, data, 0, header.length);
22.117 +
22.118 + return data;
22.119 + }
22.120 + public InputStream getDataStream() {
22.121 + return new ByteArrayInputStream(getData());
22.122 + }
22.123 +
22.124 + public File getDataFile() throws IOException {
22.125 + File f = File.createTempFile("wbmp_", "." + title, new File("."));
22.126 + FileOutputStream fos = new FileOutputStream(f);
22.127 + fos.write(getData());
22.128 + fos.flush();
22.129 + fos.close();
22.130 +
22.131 + return f;
22.132 + }
22.133 + }
22.134 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/test/sun/pisces/ScaleTest.java Mon Jun 29 14:42:22 2009 -0700
23.3 @@ -0,0 +1,58 @@
23.4 +/*
23.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
23.7 + *
23.8 + * This code is free software; you can redistribute it and/or modify it
23.9 + * under the terms of the GNU General Public License version 2 only, as
23.10 + * published by the Free Software Foundation.
23.11 + *
23.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
23.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23.15 + * version 2 for more details (a copy is included in the LICENSE file that
23.16 + * accompanied this code).
23.17 + *
23.18 + * You should have received a copy of the GNU General Public License version
23.19 + * 2 along with this work; if not, write to the Free Software Foundation,
23.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23.21 + *
23.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
23.24 + * have any questions.
23.25 + */
23.26 +
23.27 +import java.awt.*;
23.28 +import java.awt.geom.Ellipse2D;
23.29 +import java.awt.image.BufferedImage;
23.30 +import java.io.File;
23.31 +import javax.imageio.ImageIO;
23.32 +
23.33 +
23.34 +public class ScaleTest {
23.35 + public static void main(String[] args) throws Exception {
23.36 + BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
23.37 + Graphics2D g = image.createGraphics();
23.38 +
23.39 + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
23.40 + g.setPaint(Color.WHITE);
23.41 + g.fill(new Rectangle(image.getWidth(), image.getHeight()));
23.42 + g.scale(.9, .9);
23.43 + g.setPaint(Color.BLACK);
23.44 + g.setStroke(new BasicStroke(0.5f));
23.45 + g.draw(new Ellipse2D.Double(25, 25, 150, 150));
23.46 +
23.47 + // To visually check it
23.48 + //ImageIO.write(image, "PNG", new File(args[0]));
23.49 +
23.50 + boolean nonWhitePixelFound = false;
23.51 + for (int x = 100; x < 200; ++x) {
23.52 + if (image.getRGB(x, 90) != Color.WHITE.getRGB()) {
23.53 + nonWhitePixelFound = true;
23.54 + break;
23.55 + }
23.56 + }
23.57 + if (!nonWhitePixelFound) {
23.58 + throw new RuntimeException("A circle is rendered like a 'C' shape.");
23.59 + }
23.60 + }
23.61 +}