Wednesday, August 26, 2009

Dynamically change color of Node icon

While working and extending my Palette usage I had the challenge of having 6 categories and each of those an undefined number of items. Each of the items in each category had the same icon.

Now, using 6 different 16x16 and 32x32 pixel icons I suddenly got confronted with the requirement of each of those icons should be able to represent in the standard 16 web colors.

Well, it was out of the question to add 16*(6+6) = 192 different png based icons for those different options.

Using the example of created a Palette described in the "Rich Client Programming" book I had the MyItemData object which had source code like



private Image icon16;
private Image icon32;
public static final String PROP_ID = "id";
public static final String PROP_NAME = "displayName";
public static final String PROP_COMMENT = "comment";
public static final String PROP_ICON16 = "icon16";
public static final String PROP_ICON32 = "icon32";

// ...

public Image getSmallImage() {
return icon16;
}

// ...

private void loadIcons() {
String iconId = props.getProperty(PROP_ICON16);
icon16 = ImageUtilities.loadImage(iconId);
iconId = props.getProperty(PROP_ICON32);
icon32 = ImageUtilities.loadImage(iconId);
}



The idea was now to use the BufferedImage methods getRGB and setRGB to replace the color of the initial 12 png icons (which were drawn in BLACK) dynamically with a color the user has defined as one additional property.

The code to change this depends of what initial color model used in the input PNG. In my case I created the initial icons with Gimp and it was using TYPE_4BYTE_ABGR. Have that in mind when you create the new RGB value to be set for a given pixel.

The new code looks very similar and just a few changes are needed to get the desired result


private BufferedImage icon16;
private BufferedImage icon32;
public static final String PROP_ID = "id";
public static final String PROP_NAME = "displayName";
public static final String PROP_COMMENT = "comment";
public static final String PROP_COLOR = "color";
public static final String PROP_ICON16 = "icon16";
public static final String PROP_ICON32 = "icon32";

// ...

public Image getSmallImage() {
int width = icon16.getWidth();
int height = icon16.getHeight();

for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int rgb = icon16.getRGB(x, y);
if (icon16.getRGB(x, y) < 0) {
rgb = some_method_returning_the_RGB_for_a_selected_color;
icon16.setRGB(x, y, rgb);
}
}
}
return icon16;
}

// ...

private void loadIcons() {
String iconId = props.getProperty(PROP_ICON16);
icon16 = (BufferedImage)ImageUtilities.loadImage(iconId);
iconId = props.getProperty(PROP_ICON32);
icon32 = (BufferedImage)ImageUtilities.loadImage(iconId);
}




With respect to the method giving the new RGB value for a given pixel based on one of the Web Colors I simply get the alpha, red, green and blue components (via bit shifting, see for example here for a discussion) and then set the value for Red, Green and Blue depending on the Web color selected in the property. After that set the new RGB value equal to

rgb = (alpha << 24) | (red << 16) | (green << 8) | blue;

Now I can show the icons for the Palette Items in any color the user may select and only need to store one black version of them in the system

No comments:

Post a Comment