Add color to a grayscale BufferedImage - java

Can't find an answer to this, maybe its too basic. I have a gray scale BufferedImage (basically a section from a black-and-white PDF), and I'd like to draw a red box on the image. However, when I do so and save the image, the red box comes out as grey.
How to correctly add color to a gray scale BufferedImage?
I suppose I need to convert the color model(?) from gray scale to RGB? Although I don't need to convert the black and white parts of the image to color - that is to say the resulting image can be black and white. So long as I can draw a red line on the image without it saving as a shade of gray.
The image file is a GIF.

By using the following code, I could add RED rectangle to a grayscale image. See if this works for you. Else let us know what error you faced.
public static void main(String[] args) throws IOException {
BufferedImage old = ImageIO.read(new File("download.gif"));
int w = old.getWidth();
int h = old.getHeight();
BufferedImage img = new BufferedImage(
w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(old, 0, 0, null);
g2d.setColor(Color.red);
g2d.drawRect(10, 10, 100, 100);
g2d.dispose();
ImageIO.write(img, "gif", new File("out.gif"));
}

Related

Drawing a circle on a bufferedImage in Java

I want to draw a circle on a buffered image that act like a png
i want to use this circle in order to replace the mouse cursor for a paint application i am working on.
i cant download a circle png from google as i need to keep changing the size of this circle depending on the width of the tool i am using it for.
here is my attempt so far
public static BufferedImage getCircle() {
BufferedImage bufferedImage = new BufferedImage(30, 30, BufferedImage.TYPE_INT_RGB);
Color transparent = new Color(0x00FFFFFF, true);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
//trying to make the bufferedImage transparent
g.setComposite(AlphaComposite.Src);
g.setColor(transparent);
g.setBackground(transparent);
g.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
//drawing the circle
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g.drawOval(0, 0, 200, 200);
return bufferedImage;
}
it should look like:
However my code currently only creates a white square.
Your code has two problems (as already shown in the comments). The first is that you draw a circle with a radius of 200px into an image of dimensions 30px. If you closely look you can barely see a black pixel in the lower right corner.
Fix it by adjusting your dimensions such that it fits inside, for example like:
BufferedImage bufferedImage = new BufferedImage(60, 60, BufferedImage.TYPE_INT_RGB);
...
g.drawOval(5, 5, 50, 50);
Next is that you want to achieve a transparent background. To do so you need to set the type of the image to a color model which supports transparency, like ARGB (A = Alpha = transparency) instead of RGB:
BufferedImage bufferedImage = new BufferedImage(60, 60, BufferedImage.TYPE_INT_ARGB);
Last you probably want to increase the thickness of your border to achieve the image you showed. You do so by using g.setStroke(...):
g.setColor(Color.BLACK);
g.setStroke(new BasicStroke(5));
g.drawOval(5, 5, 50, 50);
With this setting you achieve the following result (with transparency):
Play with the values to adjust the circle to your exact needs.

ImageIO not printing proper color

I am trying to read a PNG image file from disk, draw some rectangles on it and save the modified image on the disk. Here's the scala code:
//l is a list of Rectangle objects of the form (x1,x2,y1,y2)
val image = ImageIO.read(sourceimage);
val graph=image.createGraphics()
graph.setColor(Color.GREEN)
l.foreach(x=>graph.draw(new java.awt.Rectangle(x.x1,x.y1,x.x2-x.x1,x.y2-x.y1)))
graph.dispose()
ImageIO.write(image,"png",new File(destimage))
The rectangles are drawn but in GREY color instead of GREEN. What am I doing wrong?
If the source image is a gray scale image, then it's unlikely that it will be capable of using any color of any sort.
Instead, you need to create a second, colored, BufferedImage and paint the original to it.
BufferedImage original = ImageIO.read(sourceimage);
BufferedImage iamge = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
g2d.drawImage(original, 0, 0, null);
// Continue with what you have
Sorry, I have no experience with PIL, but that's how you'd do it (basically) in pure Java

How to rotate and draw an image in a specific way?

I have a line. I know the endpoint of that line and an angle which tells by how many degrees it's tilted. I want to draw an image in such a way so that the bottom center point of the image would touch the endpoint of the line like so:
Sadly, I get the wanted result only if line isn't rotated, like above. If it's rotated by, for example, 90 degrees I get this:
This is the code that draws the image (line is already drawn by that point).
public void drawCreature(Graphics2D g) {
int centered = creature.getX() - creature.getImage().getWidth()/2;
BufferedImage image = creature.getImage();
BufferedImage rotatedImage = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D)rotatedImage.getGraphics();
g2d.rotate(Math.toRadians(creature.getAngle()), rotatedImage.getWidth()/2,
rotatedImage.getHeight()/2);
g2d.drawImage(creature.getImage(), 0, 0, null);
g.drawImage(rotatedImage, centered, creature.getY(), null);
}
Any help would be appreciated.

How to make a rounded corner image in Java

I want to make a image with rounded corners. A image will come from input and I will make it rounded corner then save it. I use pure java. How can I do that? I need a function like
public void makeRoundedCorner(Image image, File outputFile){
.....
}
Edit : Added an image for information.
I suggest this method that takes an image and produces an image and keeps the image IO outside:
Edit: I finally managed to make Java2D soft-clip the graphics with the help of Java 2D Trickery: Soft Clipping by Chris Campbell. Sadly, this isn't something Java2D supports out of the box with some RenderhingHint.
public static BufferedImage makeRoundedCorner(BufferedImage image, int cornerRadius) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = output.createGraphics();
// This is what we want, but it only does hard-clipping, i.e. aliasing
// g2.setClip(new RoundRectangle2D ...)
// so instead fake soft-clipping by first drawing the desired clip shape
// in fully opaque white with antialiasing enabled...
g2.setComposite(AlphaComposite.Src);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.WHITE);
g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));
// ... then compositing the image on top,
// using the white shape from above as alpha source
g2.setComposite(AlphaComposite.SrcAtop);
g2.drawImage(image, 0, 0, null);
g2.dispose();
return output;
}
Here's a test driver:
public static void main(String[] args) throws IOException {
BufferedImage icon = ImageIO.read(new File("icon.png"));
BufferedImage rounded = makeRoundedCorner(icon, 20);
ImageIO.write(rounded, "png", new File("icon.rounded.png"));
}
This it what the input/output of the above method looks like:
Input:
Ugly, jagged output with setClip():
Nice, smooth output with composite trick:
Close up of the corners on gray background (setClip() obviously left, composite right):
I am writing a follow up to Philipp Reichart's answer.
the answer of as an answer.
To remove the white background (seems to be black in the pictures), change g2.setComposite(AlphaComposite.SrcAtop);
to g2.setComposite(AlphaComposite.SrcIn);
This was a big problem for me because I have different images with transparency that I don't want to lose.
My original image:
If I use g2.setComposite(AlphaComposite.SrcAtop);:
When I use g2.setComposite(AlphaComposite.SrcIn); the background is transparent.
I found another way using TexturePaint:
ImageObserver obs = ...;
int w = img.getWidth(obs);
int h = img.getHeight(obs);
// any shape can be used
Shape clipShape = new RoundRectangle2D.Double(0, 0, w, h, 20, 20);
// create a BufferedImage with transparency
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D bg = bi.createGraphics();
// make BufferedImage fully transparent
bg.setComposite(AlphaComposite.Clear);
bg.fillRect(0, 0, w, h);
bg.setComposite(AlphaComposite.SrcOver);
// copy/paint the actual image into the BufferedImage
bg.drawImage(img, 0, 0, w, h, obs);
// set the image to be used as TexturePaint on the target Graphics
g.setPaint(new TexturePaint(bi, new Rectangle2D.Float(0, 0, w, h)));
// activate AntiAliasing
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// translate the origin to where you want to paint the image
g.translate(x, y);
// draw the Image
g.fill(clipShape);
// reset paint
g.setPaint(null);
This code can be simplified if you have a non-animated image, by creating the BufferedImage only once and keeping it for each paint.
If your image is animated though you have to recreate the BufferedImage on each paint. (Or at least i have not found a better solution for this yet.)

Custom JLabel icon

I want to use java JLabel with an Icon in custom size on my GUI. like this :
I used this code to change size of original Icon :
ImageIcon imageIcon = (ImageIcon) jLabel1.getIcon();// new ImageIcon( "Play-Hot-icon.png");
ImageIcon thumbnailIcon = new ImageIcon(getScaledImage(imageIcon.getImage(), 25 , 25));
jLabel1.setIcon(thumbnailIcon);
and here is code for resize image
private Image getScaledImage(Image srcImg, int w, int h){
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedImg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(srcImg, 0, 0, w, h, null);
g2.dispose();
return resizedImg;
}
but after resizing image and using this code the result is this! :
how can I have desired image on my JLabel??
regards,
sajad
The problem is that when you create the scaled image, you use BufferedImage.TYPE_INT_RGB for your new image, and transparency gets rendered as black with just TYPE_INT_RGB.
In order to keep transparency, you need to replace that with BufferedImage.TYPE_INT_ARGB, since you need an alpha component.
However, calling Image.getScaledInstance on imageIcon's image will return a scaled image, already with an alpha component, and you can pass it rendering hints to play with the quality of the scaled image, doing essentially the same as your getScaledImage function, but with less of the hassle.

Categories

Resources