Skip to content

Commit aff25f1

Browse files
committed
4690476: NegativeArraySizeException from AffineTransformOp with shear
Reviewed-by: psadhukhan, jdv
1 parent e93b10d commit aff25f1

File tree

2 files changed

+140
-10
lines changed

2 files changed

+140
-10
lines changed

src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 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
@@ -186,7 +186,13 @@ public final int getInterpolationType() {
186186
* {@code getBounds2D(BufferedImage)}
187187
* are not necessarily the same as the coordinates of the
188188
* {@code BufferedImage} returned by this method. If the
189-
* upper-left corner coordinates of the rectangle are
189+
* application provides a {@code dst} that is always returned.
190+
* If {@code dst} is {@code null} and a destination {code BufferedImage}
191+
* with the transformed dimensions cannot be created, the {@code src}
192+
* dimensions will be substituted.
193+
*
194+
* <p>
195+
* If the upper-left corner coordinates of the rectangle are
190196
* negative then this part of the rectangle is not drawn. If the
191197
* upper-left corner coordinates of the rectangle are positive
192198
* then the filtered image is drawn at that position in the
@@ -224,7 +230,7 @@ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
224230
BufferedImage origDst = dst;
225231

226232
if (dst == null) {
227-
dst = createCompatibleDestImage(src, null);
233+
dst = createCompatibleDestImageInt(src, null);
228234
dstCM = srcCM;
229235
origDst = dst;
230236
}
@@ -272,7 +278,7 @@ public final BufferedImage filter(BufferedImage src, BufferedImage dst) {
272278
}
273279
else {
274280
needToConvert = true;
275-
dst = createCompatibleDestImage(src, null);
281+
dst = createCompatibleDestImageInt(src, null);
276282
}
277283
}
278284

@@ -320,7 +326,12 @@ else if (origDst != dst) {
320326
* {@code getBounds2D(Raster)}
321327
* are not necessarily the same as the coordinates of the
322328
* {@code WritableRaster} returned by this method. If the
323-
* upper-left corner coordinates of rectangle are negative then
329+
* application provides a {@code dst} that is always returned.
330+
* If {@code dst} is {@code null} and a destination {code Raster}
331+
* with the transformed dimensions cannot be created, the {@code src}
332+
* dimensions will be substituted.
333+
* <p>
334+
* If the upper-left corner coordinates of rectangle are negative then
324335
* this part of the rectangle is not drawn. If the coordinates
325336
* of the rectangle are positive then the filtered image is drawn at
326337
* that position in the destination {@code Raster}.
@@ -342,7 +353,7 @@ public final WritableRaster filter(Raster src, WritableRaster dst) {
342353
throw new NullPointerException("src image is null");
343354
}
344355
if (dst == null) {
345-
dst = createCompatibleDestRaster(src);
356+
dst = createCompatibleDestRasterInt(src);
346357
}
347358
if (src == dst) {
348359
throw new IllegalArgumentException("src image cannot be the "+
@@ -422,7 +433,7 @@ else if (pts[i+1] < fminY) {
422433
/**
423434
* Creates a zeroed destination image with the correct size and number of
424435
* bands. A {@code RasterFormatException} may be thrown if the
425-
* transformed width or height is equal to 0.
436+
* transformed width or height is less than or equal to 0, or too large.
426437
* <p>
427438
* If {@code destCM} is null,
428439
* an appropriate {@code ColorModel} is used; this
@@ -437,9 +448,36 @@ else if (pts[i+1] < fminY) {
437448
*/
438449
public BufferedImage createCompatibleDestImage (BufferedImage src,
439450
ColorModel destCM) {
440-
BufferedImage image;
441451
Rectangle r = getBounds2D(src).getBounds();
452+
try {
453+
return createCompatibleDestImage(src, destCM, r);
454+
} catch (Exception e) {
455+
if (e instanceof RasterFormatException) {
456+
throw e;
457+
} else {
458+
RasterFormatException re =
459+
new RasterFormatException("Could not create transformed image of size " + r);
460+
re.initCause(e);
461+
throw re;
462+
}
463+
}
464+
}
465+
466+
private BufferedImage createCompatibleDestImageInt(BufferedImage src,
467+
ColorModel destCM) {
468+
469+
try {
470+
return createCompatibleDestImage(src, destCM);
471+
} catch (Exception e) {
472+
return createCompatibleDestImage(src, destCM, src.getRaster().getBounds());
473+
}
474+
}
442475

476+
private BufferedImage createCompatibleDestImage(BufferedImage src,
477+
ColorModel destCM,
478+
Rectangle r) {
479+
480+
BufferedImage image;
443481
// If r.x (or r.y) is < 0, then we want to only create an image
444482
// that is in the positive range.
445483
// If r.x (or r.y) is > 0, then we need to create an image that
@@ -482,14 +520,38 @@ public BufferedImage createCompatibleDestImage (BufferedImage src,
482520
/**
483521
* Creates a zeroed destination {@code Raster} with the correct size
484522
* and number of bands. A {@code RasterFormatException} may be thrown
485-
* if the transformed width or height is equal to 0.
523+
* if the transformed width or height is less than or equal to 0, or too large.
486524
*
487525
* @param src The {@code Raster} to be transformed.
488526
*
489527
* @return The zeroed destination {@code Raster}.
490528
*/
491529
public WritableRaster createCompatibleDestRaster (Raster src) {
492-
Rectangle2D r = getBounds2D(src);
530+
Rectangle r = getBounds2D(src).getBounds();
531+
try {
532+
return createCompatibleDestRaster(src, r);
533+
} catch (Exception e) {
534+
if (e instanceof RasterFormatException) {
535+
throw e;
536+
} else {
537+
RasterFormatException re =
538+
new RasterFormatException("Could not create transformed raster of size " + r);
539+
re.initCause(e);
540+
throw re;
541+
}
542+
}
543+
}
544+
545+
private WritableRaster createCompatibleDestRasterInt(Raster src) {
546+
try {
547+
return createCompatibleDestRaster(src);
548+
} catch (Exception e) {
549+
Rectangle r = src.getBounds();
550+
return createCompatibleDestRaster(src, r);
551+
}
552+
}
553+
554+
private WritableRaster createCompatibleDestRaster (Raster src, Rectangle r) {
493555

494556
return src.createCompatibleWritableRaster((int)r.getX(),
495557
(int)r.getY(),
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2017, Oracle and/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+
/**
25+
* @test
26+
* @bug 4690476
27+
* @summary Verify behaviour with transform which creates too large an image.
28+
*/
29+
30+
import java.awt.geom.AffineTransform;
31+
import java.awt.image.AffineTransformOp;
32+
import static java.awt.image.AffineTransformOp.*;
33+
import java.awt.image.BufferedImage;
34+
import java.awt.image.Raster;
35+
import java.awt.image.RasterFormatException;
36+
37+
public class AffineTxOpSizeTest {
38+
39+
static final int W = 2552, H = 3300;
40+
// This transform will require an approx 60_000 x 60_000 raster which is too large
41+
static final AffineTransform AT = new AffineTransform(0.2, 23, 18, 0.24, -70.0, -90.0);
42+
43+
public static void main(String[] args) {
44+
BufferedImage src = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB);
45+
testAOP(src, TYPE_BICUBIC);
46+
testAOP(src, TYPE_BILINEAR);
47+
testAOP(src, TYPE_NEAREST_NEIGHBOR);
48+
}
49+
50+
static void testAOP(BufferedImage src, int iType) {
51+
AffineTransformOp aop = new AffineTransformOp(AT, iType);
52+
System.out.println("Bounds=" + aop.getBounds2D(src));
53+
54+
aop.filter(src, null);
55+
aop.filter(src.getRaster(), null);
56+
try {
57+
aop.createCompatibleDestImage(src, src.getColorModel());
58+
throw new RuntimeException("No exception for image");
59+
} catch (RasterFormatException e) {
60+
}
61+
try {
62+
aop.createCompatibleDestRaster(src.getRaster());
63+
throw new RuntimeException("No exception for raster");
64+
} catch (RasterFormatException e) {
65+
}
66+
}
67+
68+
}

0 commit comments

Comments
 (0)