Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions jdk/src/share/classes/java/awt/color/ICC_Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ public class ICC_Profile implements Serializable {
private static ICC_Profile GRAYprofile;
private static ICC_Profile LINEAR_RGBprofile;

/**
* Set to {@code true} for {@code BuiltInProfile}, {@code false} otherwise.
* This flag is used in {@link #setData(int, byte[])} to prevent modifying
* built-in profiles.
*/
private final transient boolean builtIn;

/**
* Profile class is input.
Expand Down Expand Up @@ -729,16 +735,22 @@ public class ICC_Profile implements Serializable {
* Constructs an ICC_Profile object with a given ID.
*/
ICC_Profile(Profile p) {
this.cmmProfile = p;
cmmProfile = p;
builtIn = false;
}


/**
* Constructs an ICC_Profile object whose loading will be deferred.
* The ID will be 0 until the profile is loaded.
*
* <p>
* Note: {@code ProfileDeferralInfo} is used for built-in profile
* creation only, and all built-in profiles should be constructed using it.
*/
ICC_Profile(ProfileDeferralInfo pdi) {
deferralInfo = pdi;
builtIn = true;
}


Expand Down Expand Up @@ -1340,17 +1352,34 @@ static byte[] getData(Profile p, int tagSignature) {
* This method is useful for advanced applets or applications which need to
* access profile data directly.
*
* @param tagSignature The ICC tag signature for the data element
* you want to set.
* @param tagData the data to set for the specified tag signature
* @throws IllegalArgumentException if {@code tagSignature} is not a signature
* as defined in the ICC specification.
* @throws IllegalArgumentException if a content of the {@code tagData}
* array can not be interpreted as valid tag data, corresponding
* to the {@code tagSignature}.
* <p>
* Note: JDK built-in ICC Profiles cannot be updated using this method
* as it will result in {@code IllegalArgumentException}. JDK built-in
* profiles are those obtained by {@code ICC_Profile.getInstance(int colorSpaceID)}
* where {@code colorSpaceID} is one of the following:
* {@link ColorSpace#CS_sRGB}, {@link ColorSpace#CS_LINEAR_RGB},
* {@link ColorSpace#CS_PYCC}, {@link ColorSpace#CS_GRAY} or
* {@link ColorSpace#CS_CIEXYZ}.
*
* @param tagSignature the ICC tag signature for the data element you want
* to set
* @param tagData the data to set for the specified tag signature
* @throws IllegalArgumentException if {@code tagSignature} is not a
* signature as defined in the ICC specification.
* @throws IllegalArgumentException if the content of the {@code tagData}
* array can not be interpreted as valid tag data, corresponding to
* the {@code tagSignature}
* @throws IllegalArgumentException if this is a built-in profile for one
* of the pre-defined color spaces, that is those which can be obtained
* by calling {@code ICC_Profile.getInstance(int colorSpaceID)}
* @see #getData
* @see ColorSpace
*/
public void setData(int tagSignature, byte[] tagData) {
if (builtIn) {
throw new IllegalArgumentException("Built-in profile cannot be modified");
}

if (tagSignature == ICC_Profile.icSigHead) {
verifyHeader(tagData);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2025, 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 8346465
* @summary Tests if setData() throws IAE for BuiltIn profiles
*/

import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;

public class BuiltInProfileCheck {
private static final int HEADER_TAG = ICC_Profile.icSigHead;
private static final int INDEX = ICC_Profile.icHdrDeviceClass;
private static final String EXCEPTION_MSG = "Built-in profile cannot be modified";
/**
* {@link #prepareTestProfile(String, boolean, int)}
* stores the profile to test in testProfile.
*/
private static ICC_Profile testProfile;

private static final Map<Integer, String> colorSpace = new HashMap<Integer, String> () {{
put(ColorSpace.CS_sRGB, "CS_sRGB");
put(ColorSpace.CS_PYCC, "CS_PYCC");
put(ColorSpace.CS_GRAY, "CS_GRAY");
put(ColorSpace.CS_CIEXYZ, "CS_CIEXYZ");
put(ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB");
}};

public static void main(String[] args) throws Exception {
System.out.println("CASE 1: Testing BuiltIn Profile");
for (int cs : colorSpace.keySet()) {
prepareTestProfile("Default", true, cs);
testProfile(true, cs);
}
System.out.println("Passed\n");

System.out.println("CASE 2: Testing Custom Profile");
prepareTestProfile("Default", false, ColorSpace.CS_sRGB);
testProfile(false, ColorSpace.CS_sRGB);
System.out.println("Passed\n");

System.out.println("CASE 3: Testing Built-In Profile"
+ " Serialization & Deserialization");
for (int cs : colorSpace.keySet()) {
prepareTestProfile("Serialize", true, cs);
testProfile(true, cs);
}
System.out.println("Passed\n");

System.out.println("CASE 4: Testing Custom Profile"
+ " Serialization & Deserialization");
prepareTestProfile("Serialize", false, ColorSpace.CS_sRGB);
testProfile(false, ColorSpace.CS_sRGB);
System.out.println("Passed\n");

System.out.println("CASE 5: Test reading Built-In profile from .icc file");
prepareTestProfile("ReadFromFile", true, ColorSpace.CS_sRGB);
testProfile(true, ColorSpace.CS_sRGB);
System.out.println("Passed\n");

System.out.println("CASE 6: Test reading Custom profile from .icc file");
prepareTestProfile("ReadFromFile", false, ColorSpace.CS_sRGB);
testProfile(false, ColorSpace.CS_sRGB);
System.out.println("Passed\n");
}

private static void prepareTestProfile(String testCase,
boolean isBuiltIn, int cs) {
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
// if isBuiltIn=true use builtInProfile else create a copy
testProfile = isBuiltIn
? builtInProfile
: ICC_Profile.getInstance(builtInProfile.getData());

switch (testCase) {
case "Default":
// empty case block
// no further processing of testProfile required for default case
break;
case "Serialize":
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(testProfile);

byte[] array = baos.toByteArray();
try (ObjectInputStream ois =
new ObjectInputStream(new ByteArrayInputStream(array))) {
testProfile = (ICC_Profile) ois.readObject();
}
} catch (Exception e) {
throw new RuntimeException("Test Failed ! Serial-Deserialization"
+ " case failed", e);
}
break;
case "ReadFromFile":
// .icc files serialized on older JDK version
String filename = isBuiltIn ? "builtIn.icc" : "custom.icc";
String testDir = System.getProperty("test.src")
+ System.getProperty("file.separator");
filename = testDir + filename;

try (FileInputStream fileIn = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(fileIn)) {
testProfile = (ICC_Profile) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("Test Failed ! Unable to fetch"
+ " .icc files", e);
}
break;
}
}

private static void testProfile(boolean isBuiltIn, int cs) {
byte[] headerData = testProfile.getData(HEADER_TAG);
// Set profile class to valid icSigInputClass = 0x73636E72
headerData[INDEX] = 0x73;
headerData[INDEX + 1] = 0x63;
headerData[INDEX + 2] = 0x6E;
headerData[INDEX + 3] = 0x72;

if (isBuiltIn) {
System.out.println("Testing: " + colorSpace.get(cs));
try {
// Try updating a built-in profile, IAE is expected
testProfile.setData(HEADER_TAG, headerData);
throw new RuntimeException("Test Failed! IAE NOT thrown for profile "
+ colorSpace.get(cs));
} catch (IllegalArgumentException iae) {
if (!iae.getMessage().equals(EXCEPTION_MSG)) {
throw new RuntimeException("Test Failed! IAE with exception msg \""
+ EXCEPTION_MSG + "\" NOT thrown for profile "
+ colorSpace.get(cs));
}
}
} else {
// Modifying custom profile should NOT throw IAE
testProfile.setData(HEADER_TAG, headerData);
}
}
}
Binary file not shown.
Binary file not shown.
6 changes: 4 additions & 2 deletions jdk/test/java/awt/color/ICC_Profile/SetHeaderInfo.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
Expand Down Expand Up @@ -37,7 +37,9 @@ public static void main(String[] args) {
ColorSpace.CS_CIEXYZ, ColorSpace.CS_PYCC,
ColorSpace.CS_GRAY};
for (int cspace : cspaces) {
ICC_Profile icc = ICC_Profile.getInstance(cspace);
ICC_Profile builtInProfile = ICC_Profile.getInstance(cspace);
ICC_Profile icc = ICC_Profile.getInstance(builtInProfile.getData());

testSame(icc);
testCustom(icc);
// some corner cases
Expand Down
56 changes: 56 additions & 0 deletions jdk/test/java/awt/color/ICC_ProfileSetNullDataTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2004, 2025, 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.
*/

import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.util.HashMap;
import java.util.Map;

/**
* @test
* @bug 4823896 7042594
* @summary Test checks behavior of the ICC_Profile.setData(int, byte[])
*/
public final class ICC_ProfileSetNullDataTest {
private static final Map<Integer, String> colorSpace = new HashMap<Integer, String> () {{
put(ColorSpace.CS_sRGB, "CS_sRGB");
put(ColorSpace.CS_PYCC, "CS_PYCC");
put(ColorSpace.CS_GRAY, "CS_GRAY");
put(ColorSpace.CS_CIEXYZ, "CS_CIEXYZ");
put(ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB");
}};

public static void main(String[] args) {
for (int cs : colorSpace.keySet()) {
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
ICC_Profile profile = ICC_Profile.getInstance(builtInProfile.getData());
try {
profile.setData(ICC_Profile.icSigCmykData, null);
throw new RuntimeException("IAE expected, but not thrown for "
+ "ColorSpace: " + colorSpace.get(cs));
} catch (IllegalArgumentException e) {
// IAE expected
}
}
}
}
6 changes: 3 additions & 3 deletions jdk/test/sun/java2d/cmm/ProfileOp/SetDataTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2025, 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
Expand Down Expand Up @@ -29,7 +29,6 @@
* @run main SetDataTest
*/


import java.util.ArrayList;
import java.util.List;
import java.awt.color.ICC_Profile;
Expand All @@ -47,7 +46,8 @@ static class TestCase {
static byte[] invalidTRCData;

static {
profile = ICC_Profile.getInstance(CS_GRAY);
ICC_Profile builtInProfile = ICC_Profile.getInstance(CS_GRAY);
profile = ICC_Profile.getInstance(builtInProfile.getData());
validTRCdata = profile.getData(icSigGrayTRCTag);
invalidTRCData = new byte[]{0x42, 0x42, 0x42, 0x42, 1, 3, 4, 6,};
}
Expand Down