Skip to content

Commit ec3bb93

Browse files
committed
8358623: Avoid unnecessary data copying in ICC_Profile
Reviewed-by: honkar, prr
1 parent 39c9de2 commit ec3bb93

File tree

4 files changed

+115
-44
lines changed

4 files changed

+115
-44
lines changed

src/java.desktop/share/classes/java/awt/color/ICC_Profile.java

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -799,31 +799,19 @@ private interface BuiltInProfile {
799799
*/
800800
public static ICC_Profile getInstance(byte[] data) {
801801
ProfileDataVerifier.verify(data);
802+
verifyHeader(data);
802803
Profile p;
803804
try {
804-
byte[] theHeader = new byte[HEADER_SIZE];
805-
System.arraycopy(data, 0, theHeader, 0, HEADER_SIZE);
806-
verifyHeader(theHeader);
807-
808805
p = CMSManager.getModule().loadProfile(data);
809806
} catch (CMMException c) {
810807
throw new IllegalArgumentException("Invalid ICC Profile Data");
811808
}
812809

813810
try {
814-
if (getColorSpaceType(data) == ColorSpace.TYPE_GRAY
815-
&& getData(p, icSigMediaWhitePointTag) != null
816-
&& getData(p, icSigGrayTRCTag) != null) {
811+
int type = getColorSpaceType(data);
812+
if (type == ColorSpace.TYPE_GRAY) {
817813
return new ICC_ProfileGray(p);
818-
}
819-
if (getColorSpaceType(data) == ColorSpace.TYPE_RGB
820-
&& getData(p, icSigMediaWhitePointTag) != null
821-
&& getData(p, icSigRedColorantTag) != null
822-
&& getData(p, icSigGreenColorantTag) != null
823-
&& getData(p, icSigBlueColorantTag) != null
824-
&& getData(p, icSigRedTRCTag) != null
825-
&& getData(p, icSigGreenTRCTag) != null
826-
&& getData(p, icSigBlueTRCTag) != null) {
814+
} else if (type == ColorSpace.TYPE_RGB) {
827815
return new ICC_ProfileRGB(p);
828816
}
829817
} catch (CMMException c) {
@@ -969,7 +957,7 @@ private Profile cmmProfile() {
969957
* @return the major version of the profile
970958
*/
971959
public int getMajorVersion() {
972-
return getData(icSigHead)[8];
960+
return getData(cmmProfile(), icSigHead)[8];
973961
}
974962

975963
/**
@@ -978,7 +966,7 @@ public int getMajorVersion() {
978966
* @return the minor version of the profile
979967
*/
980968
public int getMinorVersion() {
981-
return getData(icSigHead)[9];
969+
return getData(cmmProfile(), icSigHead)[9];
982970
}
983971

984972
/**
@@ -991,12 +979,12 @@ public int getProfileClass() {
991979
if (info != null) {
992980
return info.profileClass;
993981
}
994-
byte[] theHeader = getData(icSigHead);
982+
byte[] theHeader = getData(cmmProfile(), icSigHead);
995983
return getProfileClass(theHeader);
996984
}
997985

998-
private static int getProfileClass(byte[] theHeader) {
999-
int theClassSig = intFromBigEndian(theHeader, icHdrDeviceClass);
986+
private static int getProfileClass(byte[] data) {
987+
int theClassSig = intFromBigEndian(data, icHdrDeviceClass);
1000988
return switch (theClassSig) {
1001989
case icSigInputClass -> CLASS_INPUT;
1002990
case icSigDisplayClass -> CLASS_DISPLAY;
@@ -1032,8 +1020,8 @@ public int getColorSpaceType() {
10321020
return getColorSpaceType(theHeader);
10331021
}
10341022

1035-
private static int getColorSpaceType(byte[] theHeader) {
1036-
int theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1023+
private static int getColorSpaceType(byte[] data) {
1024+
int theColorSpaceSig = intFromBigEndian(data, icHdrColorSpace);
10371025
return iccCStoJCS(theColorSpaceSig);
10381026
}
10391027

@@ -1051,13 +1039,13 @@ private static int getColorSpaceType(byte[] theHeader) {
10511039
* {@code ColorSpace} class
10521040
*/
10531041
public int getPCSType() {
1054-
byte[] theHeader = getData(icSigHead);
1042+
byte[] theHeader = getData(cmmProfile(), icSigHead);
10551043
return getPCSType(theHeader);
10561044
}
10571045

1058-
private static int getPCSType(byte[] theHeader) {
1059-
int thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1060-
int theDeviceClass = intFromBigEndian(theHeader, icHdrDeviceClass);
1046+
private static int getPCSType(byte[] data) {
1047+
int thePCSSig = intFromBigEndian(data, icHdrPcs);
1048+
int theDeviceClass = intFromBigEndian(data, icHdrDeviceClass);
10611049

10621050
if (theDeviceClass == icSigLinkClass) {
10631051
return iccCStoJCS(thePCSSig);
@@ -1120,18 +1108,27 @@ public byte[] getData() {
11201108
* @see #setData(int, byte[])
11211109
*/
11221110
public byte[] getData(int tagSignature) {
1123-
byte[] t = getData(cmmProfile(), tagSignature);
1124-
return t != null ? t.clone() : null;
1125-
}
1126-
1127-
private static byte[] getData(Profile p, int tagSignature) {
11281111
try {
1129-
return CMSManager.getModule().getTagData(p, tagSignature);
1112+
return getData(cmmProfile(), tagSignature).clone();
11301113
} catch (CMMException c) {
11311114
return null;
11321115
}
11331116
}
11341117

1118+
/**
1119+
* Returns a particular tagged data element from the profile as a non-null
1120+
* byte array. The returned byte array is not cloned. It must not be exposed
1121+
* to or used by public APIs. It is intended strictly for internal use only.
1122+
*
1123+
* @param p the CMM profile from which to retrieve the tag data
1124+
* @param tagSignature the ICC tag signature for the data to retrieve
1125+
* @return a non-null byte array containing the tag data
1126+
* @throws CMMException if the specified tag doesn't exist
1127+
*/
1128+
static byte[] getData(Profile p, int tagSignature) {
1129+
return CMSManager.getModule().getTagData(p, tagSignature);
1130+
}
1131+
11351132
/**
11361133
* Sets a particular tagged data element in the profile from a byte array.
11371134
* The array should contain data in a format, corresponded to the
@@ -1183,15 +1180,15 @@ private static void verifyHeader(byte[] data) {
11831180
checkRenderingIntent(data);
11841181
}
11851182

1186-
private static void checkRenderingIntent(byte[] header) {
1183+
private static void checkRenderingIntent(byte[] data) {
11871184
int index = ICC_Profile.icHdrRenderingIntent;
11881185
/*
11891186
* ICC spec: only the least-significant 16 bits encode the rendering
11901187
* intent. The most significant 16 bits must be zero and can be ignored.
11911188
* https://www.color.org/specification/ICC.1-2022-05.pdf, section 7.2.15
11921189
*/
11931190
// Extract 16-bit unsigned rendering intent (0–65535)
1194-
int intent = (header[index + 2] & 0xff) << 8 | header[index + 3] & 0xff;
1191+
int intent = (data[index + 2] & 0xff) << 8 | data[index + 3] & 0xff;
11951192
// Only check upper bound since intent can't be negative
11961193
if (intent > icICCAbsoluteColorimetric) {
11971194
throw new IllegalArgumentException(
@@ -1212,7 +1209,7 @@ public int getNumComponents() {
12121209
if (info != null) {
12131210
return info.numComponents;
12141211
}
1215-
byte[] theHeader = getData(icSigHead);
1212+
byte[] theHeader = getData(cmmProfile(), icSigHead);
12161213
int theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
12171214
return switch (theColorSpaceSig) {
12181215
case icSigGrayData -> 1;
@@ -1251,7 +1248,7 @@ float[] getMediaWhitePoint() {
12511248
* encoded in an XYZType tag.
12521249
*/
12531250
final float[] getXYZTag(int tagSignature) {
1254-
byte[] theData = getData(tagSignature);
1251+
byte[] theData = getData(cmmProfile(), tagSignature);
12551252
float[] theXYZNumber = new float[3]; /* array to return */
12561253

12571254
/* convert s15Fixed16Number to float */
@@ -1275,7 +1272,7 @@ final float[] getXYZTag(int tagSignature) {
12751272
* single gamma value
12761273
*/
12771274
float getGamma(int tagSignature) {
1278-
byte[] theTRCData = getData(tagSignature);
1275+
byte[] theTRCData = getData(cmmProfile(), tagSignature);
12791276
if (intFromBigEndian(theTRCData, icCurveCount) != 1) {
12801277
throw new ProfileDataException("TRC is not a gamma");
12811278
}
@@ -1306,7 +1303,7 @@ float getGamma(int tagSignature) {
13061303
* table
13071304
*/
13081305
short[] getTRC(int tagSignature) {
1309-
byte[] theTRCData = getData(tagSignature);
1306+
byte[] theTRCData = getData(cmmProfile(), tagSignature);
13101307
int nElements = intFromBigEndian(theTRCData, icCurveCount);
13111308
if (nElements == 1) {
13121309
throw new ProfileDataException("TRC is not a table");

src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2021, 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
@@ -74,10 +74,15 @@ public final class ICC_ProfileGray extends ICC_Profile {
7474
private static final long serialVersionUID = -1124721290732002649L;
7575

7676
/**
77-
* Constructs a new {@code ICC_ProfileGray} from a CMM ID.
77+
* Constructs a new {@code ICC_ProfileGray} from the specified CMM profile.
78+
*
79+
* @param p the CMM profile used to create this ICC profile
80+
* @throws CMMException if the required tags are missing
7881
*/
7982
ICC_ProfileGray(Profile p) {
8083
super(p);
84+
getData(p, icSigMediaWhitePointTag);
85+
getData(p, icSigGrayTRCTag);
8186
}
8287

8388
/**

src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2022, 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
@@ -104,12 +104,20 @@ public final class ICC_ProfileRGB extends ICC_Profile {
104104
public static final int BLUECOMPONENT = 2;
105105

106106
/**
107-
* Constructs an new {@code ICC_ProfileRGB} from a CMM ID.
107+
* Constructs a new {@code ICC_ProfileRGB} from the specified CMM profile.
108108
*
109-
* @param p the CMM ID for the profile.
109+
* @param p the CMM profile used to create this ICC profile
110+
* @throws CMMException if the required tags are missing
110111
*/
111112
ICC_ProfileRGB(Profile p) {
112113
super(p);
114+
getData(p, icSigMediaWhitePointTag);
115+
getData(p, icSigRedColorantTag);
116+
getData(p, icSigGreenColorantTag);
117+
getData(p, icSigBlueColorantTag);
118+
getData(p, icSigRedTRCTag);
119+
getData(p, icSigGreenTRCTag);
120+
getData(p, icSigBlueTRCTag);
113121
}
114122

115123
/**
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.ColorSpace;
25+
import java.awt.color.ICC_Profile;
26+
27+
/**
28+
* @test
29+
* @bug 8358623
30+
* @summary Verifies ICC profile version of built-in color spaces
31+
*/
32+
public final class CheckVersions {
33+
34+
public static void main(String[] args) {
35+
test(ColorSpace.CS_CIEXYZ, 2, 3, 0);
36+
test(ColorSpace.CS_GRAY, 2, 3, 0);
37+
test(ColorSpace.CS_LINEAR_RGB, 2, 3, 0);
38+
test(ColorSpace.CS_PYCC, 4, 0, 0);
39+
test(ColorSpace.CS_sRGB, 2, 3, 0);
40+
}
41+
42+
private static void test(int cs, int expMajor, int expMinor, int expPatch) {
43+
ICC_Profile profile = ICC_Profile.getInstance(cs);
44+
45+
int major = profile.getMajorVersion();
46+
int minorRaw = profile.getMinorVersion();
47+
int minor = (minorRaw >> 4) & 0x0F;
48+
int patch = minorRaw & 0x0F;
49+
50+
if (major != expMajor || minor != expMinor || patch != expPatch) {
51+
System.err.println("Expected major: " + expMajor);
52+
System.err.println("Expected minor: " + expMinor);
53+
System.err.println("Expected patch: " + expPatch);
54+
55+
System.err.println("Actual major: " + major);
56+
System.err.println("Actual minor: " + minor);
57+
System.err.println("Actual patch: " + patch);
58+
throw new RuntimeException("Test failed for ColorSpace: " + cs);
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)