Advanced BufferedImage manipulation in pure Java

Hi guys,
I use BufferedImages to display my sprites and animations in my game. It works really fine and now I want to make things “fancy” :smiley:
On Stack Overflow did I found a way to manipulate an given image into a grayscale one. But how do I ink my images?
Given is a BufferedImage like this png:

[tr]
[td]given Image[/td]
[td]grayscaled[/td]
[td]inked[/td]
[/tr]
[tr]
[td]

[/td]
[td]

[/td]
[td]

[/td]
[/tr]

Red is just an example. I want to hand over a color and get the inked image as result.
My grayscale Code looks like this:


	public static BufferedImage getGrayScaleImage(BufferedImage original) {
 
		GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
		GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
		 
		// If the source image has no alpha info use Transparency.OPAQUE instead
		BufferedImage image = graphicsConfiguration.createCompatibleImage(original.getWidth(null), original.getHeight(null), Transparency.BITMASK);
		 
		// Copy image to buffered image
		Graphics graphics = image.createGraphics();
		 
		// Paint the image onto the buffered image
		graphics.drawImage(original, 0, 0, null);
		graphics.dispose();
		 
		// Convert to grayscale
		ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
		ColorConvertOp op = new ColorConvertOp(cs, null);
		 
		image = op.filter(image, null);
		 
		return image;
	}

I haven’t used ColorSpace or ColorConvertOp ever, so I don’t how to use them ???

My second question is a bit more tricky. Like I said: I use images with transparent backgrounds. If I defeat an enemy, I want it to scatter like glas. Is there a way to do so? If so, how?

you can implement the BufferedImageOps abstract class for that.

Scatter like glass: this is pretty tricky. You could triangulate a quad in a seemingly random way (or just a pre-split way) as if it’s a pane of glass that cracked. Then you’d give each “shard” a force going away from the center of the image. To render a shard you’d need to use TexturePaint to map that part of the image onto the triangle.

Pretty tricky with java2d and may not perform too well when you have lots of effects. It sounds like you’re interested in graphics programming, maybe it’s time to move up to OpenGL and shaders? :slight_smile:

Okay, I think I’ll drop the glass scattering ;D I don’t want to use external libs fo this project.

hello man

this is some of my code to make operation on images at run time in pure java it can help you

it help you to make this kind of operation on the images BRIGHTEN and TRANSPARENCY using lookup tables

use it is very easy just create the object and run a method



BufferedImage myImmage = ....
BufferedImage effectImmage = null; //image altered by the effect

BrightenEffect effect = new BrightenEffect();
effectImmage  = effect.filterImage(myImmage,200,150,1,1); //BRIGHTEN effect on R and G channel



package it.game.image.effect;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.LookupOp;
import java.awt.image.LookupTable;
import java.awt.image.ShortLookupTable;

public class BrightenEffect{

	short[] noChange;			//used to channel that don't change see the hapha channel
	short[] saturation;			//used to channel that don't change see the hapha channel	
	short[] unsaturation;		//used to channel that don't change see the hapha channel	

	public BrightenEffect(){
		noChange = calculateArrayNoChange();
		saturation = calculateArrayByCostant((short) 255);
		unsaturation = calculateArrayByCostant((short)0);
	}

	public BufferedImage copyImage(BufferedImage image){
		BufferedImage sourceBI = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = (Graphics2D) sourceBI.getGraphics();
		g.drawImage(image, 0, 0, null);
		return sourceBI;
	}
	
	protected short[] calculateArrayByPercentage(double percentage) {
		
		if(percentage == 0) //COLOR_UNSATURATION
			return unsaturation;
		if(percentage == 1) //COLOR_ORIGINAL
			return noChange;		
		if(percentage == 255) //COLOR_SATURATION
			return saturation;
		
		short[] array = new short[256];
		short value;
		for (int i = 0; i < array.length; i++) {
			value = (short) (i*percentage);
			if(value> 255){
				value = 255;
			}
			if(value< 0){
				value = 0;
			}
			array[i] = value;
		}
		return array;
	}		

	private short[] calculateArrayNoChange() {
		short[] array = new short[256];
		for(int i=0; i < 256; i++) {
			array[i] = (short) i;
		}
		return array;
	}	
	
	private short[] calculateArrayByCostant(short constant) {
		short[] array = new short[256];
		for(int i=0; i < 256; i++) {
			array[i] = constant;
		}
		return array;
	}	



	/**
	 * create a copy of the image changing the saturation on the 3 base color
	 * the values of the color RChannel,GChannel,BChannel must be a value between 0 and 255 
	 * is possible to change also the transparency of the image changing the alphaChannel
	 * 
	 * if the value of a  channel is 1 no change are done to that color
	 * 
	 * so call the function with the the value (image,1,1,1,1) return an image identical to the original
	 * so call the function with the value (image,1,0,0,1) return an image using the original red channel active and removing the other channels
	 * so call the function with the value (image,255,0,0,1) return an image completely red
     * so call the function with the value (image,1,1,1,0.1) return an image transparent   
	 * 
	 * etc....
	 * 
	 * 
	 * @param image
	 * @param RChannel
	 * @param GChannel
	 * @param BChannel
	 * @return
	 * @throws Exception
	 */
	public BufferedImage filterImage(BufferedImage image, double RChannel, double GChannel, double BChannel,double alphaChannel) throws Exception {

		if(RChannel == 1 && GChannel == 1 && BChannel == 1)
			return image;
		
		BufferedImage source = copyImage(image);
		
		short[] R = calculateArrayByPercentage(RChannel);
		short[] G = calculateArrayByPercentage(GChannel);
		short[] B = calculateArrayByPercentage(BChannel);
		short[] A = calculateArrayByPercentage(alphaChannel);			
			
		short[][] table;
	
		table = new short[4][];
		table[0] = R;			//RED
		table[1] = G;			//GREEN
		table[2] = B;			//BLUE
		table[3] = A;    //ALPHA
	
		LookupTable lkTable = new ShortLookupTable(0, table);
		LookupOp operation = new LookupOp(lkTable, null);

		return operation.filter(source, null);
	}		

}




Wow, thanks. I altered your code a bit to fit my needs, but it works like a charm :-*