Skip to content

Commit 49f1081

Browse files
committed
8366208: Unexpected exception in sun.java2d.cmm.lcms.LCMSImageLayout
Backport-of: 12e6a0b6d0086caf156cf5513a604320c619b856
1 parent 3e41a78 commit 49f1081

File tree

2 files changed

+177
-7
lines changed

2 files changed

+177
-7
lines changed

src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,9 @@ private LCMSImageLayout() {
125125
static LCMSImageLayout createImageLayout(BufferedImage image) {
126126
LCMSImageLayout l = new LCMSImageLayout();
127127

128-
switch (image.getType()) {
128+
Raster raster = image.getRaster();
129+
int type = image.getType();
130+
switch (type) {
129131
case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB:
130132
l.pixelType = PT_ARGB_8 ^ SWAP_ENDIAN;
131133
break;
@@ -164,19 +166,21 @@ static LCMSImageLayout createImageLayout(BufferedImage image) {
164166
return null;
165167
}
166168
}
167-
return createImageLayout(image.getRaster(), cm);
169+
return createImageLayout(raster, cm);
168170
}
169171
return null;
170172
}
171173

172174
l.width = image.getWidth();
173175
l.height = image.getHeight();
174176

175-
switch (image.getType()) {
177+
switch (type) {
176178
case BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB,
177179
BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR ->
178180
{
179-
var intRaster = (IntegerComponentRaster) image.getRaster();
181+
if (!(raster instanceof IntegerComponentRaster intRaster)) {
182+
return null;
183+
}
180184
l.nextRowOffset = safeMult(4, intRaster.getScanlineStride());
181185
l.nextPixelOffset = safeMult(4, intRaster.getPixelStride());
182186
l.offset = safeMult(4, intRaster.getDataOffset(0));
@@ -188,7 +192,9 @@ static LCMSImageLayout createImageLayout(BufferedImage image) {
188192
BufferedImage.TYPE_4BYTE_ABGR,
189193
BufferedImage.TYPE_4BYTE_ABGR_PRE ->
190194
{
191-
var byteRaster = (ByteComponentRaster) image.getRaster();
195+
if (!(raster instanceof ByteComponentRaster byteRaster)) {
196+
return null;
197+
}
192198
l.nextRowOffset = byteRaster.getScanlineStride();
193199
l.nextPixelOffset = byteRaster.getPixelStride();
194200
int firstBand = byteRaster.getSampleModel().getNumBands() - 1;
@@ -198,7 +204,9 @@ static LCMSImageLayout createImageLayout(BufferedImage image) {
198204
l.dataType = DT_BYTE;
199205
}
200206
case BufferedImage.TYPE_USHORT_GRAY -> {
201-
var shortRaster = (ShortComponentRaster) image.getRaster();
207+
if (!(raster instanceof ShortComponentRaster shortRaster)) {
208+
return null;
209+
}
202210
l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride());
203211
l.nextPixelOffset = safeMult(2, shortRaster.getPixelStride());
204212
l.offset = safeMult(2, shortRaster.getDataOffset(0));
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.Color;
25+
import java.awt.Point;
26+
import java.awt.color.ColorSpace;
27+
import java.awt.image.BufferedImage;
28+
import java.awt.image.ColorConvertOp;
29+
import java.awt.image.ColorModel;
30+
import java.awt.image.SampleModel;
31+
import java.awt.image.WritableRaster;
32+
import java.io.File;
33+
34+
import javax.imageio.ImageIO;
35+
36+
import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
37+
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR;
38+
import static java.awt.image.BufferedImage.TYPE_4BYTE_ABGR_PRE;
39+
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
40+
import static java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE;
41+
import static java.awt.image.BufferedImage.TYPE_INT_BGR;
42+
import static java.awt.image.BufferedImage.TYPE_INT_RGB;
43+
import static java.awt.image.BufferedImage.TYPE_USHORT_GRAY;
44+
45+
/**
46+
* @test
47+
* @bug 8366208
48+
* @summary Verifies ColorConvertOp works correctly with BufferedImage and
49+
* semi-custom raster
50+
*/
51+
public final class FilterSemiCustomImages {
52+
53+
private static final int W = 144;
54+
private static final int H = 123;
55+
56+
private static final int[] TYPES = {
57+
TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_INT_ARGB_PRE, TYPE_INT_BGR,
58+
TYPE_3BYTE_BGR, TYPE_4BYTE_ABGR, TYPE_4BYTE_ABGR_PRE,
59+
TYPE_USHORT_GRAY
60+
};
61+
62+
private static final int[] CSS = {
63+
ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB,
64+
ColorSpace.CS_PYCC, ColorSpace.CS_sRGB
65+
};
66+
67+
private static final class CustomRaster extends WritableRaster {
68+
CustomRaster(SampleModel sampleModel, Point origin) {
69+
super(sampleModel, origin);
70+
}
71+
}
72+
73+
public static void main(String[] args) throws Exception {
74+
for (int fromIndex : CSS) {
75+
for (int toIndex : CSS) {
76+
if (fromIndex != toIndex) {
77+
for (int type : TYPES) {
78+
test(fromIndex, toIndex, type);
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
private static void test(int fromIndex, int toIndex, int type)
86+
throws Exception
87+
{
88+
ColorSpace fromCS = ColorSpace.getInstance(fromIndex);
89+
ColorSpace toCS = ColorSpace.getInstance(toIndex);
90+
ColorConvertOp op = new ColorConvertOp(fromCS, toCS, null);
91+
92+
// standard source -> standard dst
93+
BufferedImage srcGold = new BufferedImage(W, H, type);
94+
fill(srcGold);
95+
BufferedImage dstGold = new BufferedImage(W, H, type);
96+
op.filter(srcGold, dstGold);
97+
98+
// custom source -> standard dst
99+
BufferedImage srcCustom = makeCustomBI(srcGold);
100+
fill(srcCustom);
101+
BufferedImage dst = new BufferedImage(W, H, type);
102+
op.filter(srcCustom, dst);
103+
verify(dstGold, dst);
104+
105+
// standard source -> custom dst
106+
BufferedImage src = new BufferedImage(W, H, type);
107+
fill(src);
108+
BufferedImage dstCustom = makeCustomBI(dstGold);
109+
op.filter(src, dstCustom);
110+
verify(dstGold, dstCustom);
111+
112+
// custom source -> custom dst
113+
srcCustom = makeCustomBI(srcGold);
114+
fill(srcCustom);
115+
dstCustom = makeCustomBI(dstGold);
116+
op.filter(srcCustom, dstCustom);
117+
verify(dstGold, dstCustom);
118+
}
119+
120+
private static BufferedImage makeCustomBI(BufferedImage bi) {
121+
ColorModel cm = bi.getColorModel();
122+
SampleModel sm = bi.getSampleModel();
123+
CustomRaster cr = new CustomRaster(sm, new Point());
124+
return new BufferedImage(cm, cr, bi.isAlphaPremultiplied(), null) {
125+
@Override
126+
public int getType() {
127+
return bi.getType();
128+
}
129+
};
130+
}
131+
132+
private static void fill(BufferedImage image) {
133+
int width = image.getWidth();
134+
int height = image.getHeight();
135+
for (int x = 0; x < width; ++x) {
136+
for (int y = 0; y < height; ++y) {
137+
// alpha channel may be calculated slightly differently on
138+
// different code paths, so only check fully transparent and
139+
// fully opaque pixels
140+
Color c = new Color(y * 255 / (height - 1),
141+
x * 255 / (width - 1),
142+
x % 255,
143+
(x % 2 == 0) ? 0 : 255);
144+
image.setRGB(x, y, c.getRGB());
145+
}
146+
}
147+
}
148+
149+
private static void verify(BufferedImage dstGold, BufferedImage dst)
150+
throws Exception
151+
{
152+
for (int x = 0; x < W; ++x) {
153+
for (int y = 0; y < H; ++y) {
154+
if (dst.getRGB(x, y) != dstGold.getRGB(x, y)) {
155+
ImageIO.write(dst, "png", new File("custom.png"));
156+
ImageIO.write(dstGold, "png", new File("gold.png"));
157+
throw new RuntimeException("Test failed.");
158+
}
159+
}
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)