I have the original image:
I rotate the image with the following Java code:
BufferedImage bi = ImageHelper.rotateImage(bi, -imageSkewAngle);
ImageIO.write(bi, "PNG", new File("out.png"));
as the result I have the following image:
How to remove black bound around the image and make it a proper white rectangle and to not spent much space.. use only the required size for the transformation... equal to original or larger if needed?
The following program contains a method rotateImage that should be equivalent to the rotateImage method that was used in the question: It computes the bounds of the rotated image, creates a new image with the required size, and paints the original image into the center of the new one.
The method additionally receives a Color backgroundColor that determines the background color. In the example, this is set to Color.RED, to illustrate the effect.
The example also contains a method rotateImageInPlace. This method will always create an image that has the same size as the input image, and will also paint the (rotated) original image into the center of this image.
The program creates two panels, the left one showing the result of rotateImage and the right one the result of rotateImageInPlace, together with a slider that allows changing the rotation angle. So the output of this program is shown here:
(Again, Color.RED is just used for illustration. Change it to Color.WHITE for your application)
As discussed in the comments, the goal of not changing the image size may not always be achievable, depending on the contents of the image and the angle of rotation. So for certain angles, the rotated image may not fit into the resulting image. But for the use case of the question, this should be OK: The use case is that the original image already contains a rotated rectangular "region of interest". So the parts that do not appear in the output should usually be the parts of the input image that do not contain relevant information anyhow.
(Otherwise, it would be necessary to either provide more information about the structure of the input image, regarding the border size or the angle of rotation, or one would have to manually figure out the required size by examining the image, pixel by pixel, to see which pixels are black and which ones are white)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
public class RotateImageWithoutBorder
{
public static void main(String[] args) throws Exception
{
BufferedImage image =
ImageIO.read(new URL("https://i.stack.imgur.com/tMtFh.png"));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImagePanel imagePanel0 = new ImagePanel();
imagePanel0.setBackground(Color.BLUE);
ImagePanel imagePanel1 = new ImagePanel();
imagePanel1.setBackground(Color.BLUE);
JSlider slider = new JSlider(0, 100, 1);
slider.addChangeListener(e ->
{
double alpha = slider.getValue() / 100.0;
double angleRad = alpha * Math.PI * 2;
BufferedImage rotatedImage = rotateImage(
image, angleRad, Color.RED);
imagePanel0.setImage(rotatedImage);
BufferedImage rotatedImageInPlace = rotateImageInPlace(
image, angleRad, Color.RED);
imagePanel1.setImage(rotatedImageInPlace);
f.repaint();
});
slider.setValue(0);
f.getContentPane().add(slider, BorderLayout.SOUTH);
JPanel imagePanels = new JPanel(new GridLayout(1,2));
imagePanels.add(imagePanel0);
imagePanels.add(imagePanel1);
f.getContentPane().add(imagePanels, BorderLayout.CENTER);
f.setSize(800,500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static BufferedImage rotateImage(
BufferedImage image, double angleRad, Color backgroundColor)
{
int w = image.getWidth();
int h = image.getHeight();
AffineTransform at = AffineTransform.getRotateInstance(
angleRad, w * 0.5, h * 0.5);
Rectangle rotatedBounds = at.createTransformedShape(
new Rectangle(0, 0, w, h)).getBounds();
BufferedImage result = new BufferedImage(
rotatedBounds.width, rotatedBounds.height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = result.createGraphics();
g.setColor(backgroundColor);
g.fillRect(0, 0, rotatedBounds.width, rotatedBounds.height);
at.preConcatenate(AffineTransform.getTranslateInstance(
-rotatedBounds.x, -rotatedBounds.y));
g.transform(at);
g.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(image, 0, 0, null);
g.dispose();
return result;
}
private static BufferedImage rotateImageInPlace(
BufferedImage image, double angleRad, Color backgroundColor)
{
int w = image.getWidth();
int h = image.getHeight();
AffineTransform at = AffineTransform.getRotateInstance(
angleRad, w * 0.5, h * 0.5);
Rectangle rotatedBounds = at.createTransformedShape(
new Rectangle(0, 0, w, h)).getBounds();
BufferedImage result = new BufferedImage(
w, h,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = result.createGraphics();
g.setColor(backgroundColor);
g.fillRect(0, 0, w, h);
at.preConcatenate(AffineTransform.getTranslateInstance(
-rotatedBounds.x - (rotatedBounds.width - w) * 0.5,
-rotatedBounds.y - (rotatedBounds.height - h) * 0.5));
g.transform(at);
g.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(image, 0, 0, null);
g.dispose();
return result;
}
static class ImagePanel extends JPanel
{
private BufferedImage image;
public void setImage(BufferedImage image)
{
this.image = image;
repaint();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image != null)
{
g.drawImage(image, 0, 0, null);
}
}
}
}
Related
My GUI output is picture 1. I want to print the card in the opposite direction, as in picture 2. I use JLabel to store each card as my code shown. Any .swing or .awt method can help me do this?
CardLabel = LabelCard(cardsInHand);
int xcoordinate = 100;
for ( JLabel Label : CardLabel){
this.add(Label);
Label.setBounds(i += 20 , (int) (frame.getHeight()/5.8 * game.getCurrentIdx() +20 ) , Label.getIcon().getIconWidth(), Label.getIcon().getIconHeight() );
}
Picture 1:
Picture 2:
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
-----------------------------------------------------------------------------
public static BufferedImage FlippTheImage(BufferedImage bi) {
BufferedImage flipped = new BufferedImage(bi.getWidth(), bi.getHeight(),
bi.getType());
AffineTransform tran = AffineTransform.getTranslateInstance(0,
bi.getHeight());
AffineTransform flip = AffineTransform.getScaleInstance(1d, -1d);
tran.concatenate(flip);
Graphics2D g = flipped.createGraphics();
g.setTransform(tran);
g.drawImage(bi, 0, 0, null);
g.dispose();
return flipped;
}
in this example im using AffineTransform to flip the image you can see the doumentation for more details https://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html
you can convert your icon in jlabel to bufffered image by this approach
public BufferedImage getLabelTOBufferImg(){
BufferedImage img;
int imgW, imgH,
Icon icon = lable.getIcon();
imgW = icon.getIconWidth();
imgH = icon.getIconHeight();
img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
return img;
}
I saw a thread on converting a BufferedImage to an array of pixels/bytes. Using getRGB directly on the image works, but is not ideal as it is too slow to gather all pixels. I tried the alternate way of simply grabbing the pixel data.
//convert canvas to bufferedimage
BufferedImage img = new BufferedImage(500, 500, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g2 = img.createGraphics();
canvas.printAll(g2);
g2.dispose();
System.out.println(img.getRGB(0, 0)); //-16777216 works but not ideal
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
for(byte b : pixels){
System.out.println(b); //all 0 doesnt work
}
However, the whole byte array seems to be empty (filled with 0s).
I don't know what canvas means in your code but this works perfectly:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
public class Px {
public static void main(String[] args) {
new Px().go();
}
private void go() {
BufferedImage img = new BufferedImage(5, 5, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.red);
g2.fillRect(0, 0, 2, 2);
g2.dispose();
byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
for (byte b : pixels) {
System.out.print(b + ",");
}
}
}
The result is this:
0,0,-1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
The color order is blue green red. So my red rect appears as bytes in 0,0,-1,0,0,-1 etc. I assume that -1 is 'the same' as 255.
You could explore your line canvas.printAll(). Maybe the canvas only contains black pixels.
I have some .jpg's that I'm displaying in a panel. Unfortunately they're all about 1500x1125 pixels, which is way too big for what I'm going for. Is there a programmatic way to change the resolution of these .jpg's?
You can scale an image using Graphics2D methods (from java.awt). This tutorial at mkyong.com explains it in depth.
Load it as an ImageIcon and this'll do the trick:
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public static ImageIcon resizeImageIcon( ImageIcon imageIcon , Integer width , Integer height )
{
BufferedImage bufferedImage = new BufferedImage( width , height , BufferedImage.TRANSLUCENT );
Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.drawImage( imageIcon.getImage() , 0 , 0 , width , height , null );
graphics2D.dispose();
return new ImageIcon( bufferedImage , imageIcon.getDescription() );
}
you can try:
private BufferedImage getScaledImage(Image srcImg, int w, int h) {
BufferedImage resizedImg = new BufferedImage(w, h, Transparency.TRANSLUCENT);
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;
}
From the original question (below), I am now offering a bounty for the following:
An AlphaComposite based solution for rounded corners.
Please demonstrate with a JPanel.
Corners must be completely transparent.
Must be able to support JPG painting, but still have rounded corners
Must not use setClip (or any clipping)
Must have decent performance
Hopefully someone picks this up quick, it seems easy.
I will also award the bounty if there is a well-explained reason why this can never be done, that others agree with.
Here is a sample image of what I have in mind (but usingAlphaComposite)
Original question
I've been trying to figure out a way to do rounded corners using compositing, very similar to How to make a rounded corner image in Java or http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html.
However, my attempts without an intermediate BufferedImage don't work - the rounded destination composite apparently doesn't affect the source. I've tried different things but nothing works. Should be getting a rounded red rectangle, instead I'm getting a square one.
So, I have two questions, really:
1) Is there a way to make this work?
2) Will an intermediate image actually generate better performance?
SSCCE:
the test panel TPanel
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JLabel;
public class TPanel extends JLabel {
int w = 300;
int h = 200;
public TPanel() {
setOpaque(false);
setPreferredSize(new Dimension(w, h));
setMaximumSize(new Dimension(w, h));
setMinimumSize(new Dimension(w, h));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Yellow is the clipped area.
g2d.setColor(Color.yellow);
g2d.fillRoundRect(0, 0, w, h, 20, 20);
g2d.setComposite(AlphaComposite.Src);
// Red simulates the image.
g2d.setColor(Color.red);
g2d.setComposite(AlphaComposite.SrcAtop);
g2d.fillRect(0, 0, w, h);
}
}
and its Sandbox
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class Sandbox {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setMinimumSize(new Dimension(800, 600));
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
TPanel pnl = new TPanel();
f.getContentPane().add(pnl);
f.setVisible(true);
}
}
With respect to your performance concerns the Java 2D Trickery article contains a link to a very good explanation by Chet Haase on the usage of Intermediate Images.
I think the following excerpt from O'Reilly's Java Foundation Classes in a Nutshell could be helpful to you in order to make sense of the AlphaComposite behaviour and why intermediate images may be the necessary technique to use.
The AlphaComposite Compositing Rules
The SRC_OVER compositing rule draws a possibly translucent source
color over the destination color. This is what we typically want to
happen when we perform a graphics operation. But the AlphaComposite
object actually allows colors to be combined according to seven other
rules as well.
Before we consider the compositing rules in detail, there is an
important point you need to understand. Colors displayed on the screen
never have an alpha channel. If you can see a color, it is an opaque
color. The precise color value may have been chosen based on a
transparency calculation, but, once that color is chosen, the color
resides in the memory of a video card somewhere and does not have an
alpha value associated with it. In other words, with on-screen
drawing, destination pixels always have alpha values of 1.0.
The situation is different when you are drawing into an off-screen
image, however. As you'll see when we consider the Java 2D
BufferedImage class later in this chapter, you can specify the desired
color representation when you create an off-screen image. By default,
a BufferedImage object represents an image as an array of RGB colors,
but you can also create an image that is an array of ARGB colors. Such
an image has alpha values associated with it, and when you draw into
the images, the alpha values remain associated with the pixels you
draw.
This distinction between on-screen and off-screen drawing is important
because some of the compositing rules perform compositing based on the
alpha values of the destination pixels, rather than the alpha values
of the source pixels. With on-screen drawing, the destination pixels
are always opaque (with alpha values of 1.0), but with off-screen
drawing, this need not be the case. Thus, some of the compositing
rules only are useful when you are drawing into off-screen images that
have an alpha channel.
To overgeneralize a bit, we can say that when you are drawing
on-screen, you typically stick with the default SRC_OVER compositing
rule, use opaque colors, and vary the alpha value used by the
AlphaComposite object. When working with off-screen images that have
alpha channels, however, you can make use of other compositing rules.
In this case, you typically use translucent colors and translucent
images and an AlphaComposite object with an alpha value of 1.0.
I have looked into this issue and cannot see how to do this in a single call to system classes.
Graphics2D is an abstract instance, implemented as SunGraphics2D. The source code is available at for example docjar, and so we could potentially just 'do the same, but different' by copy some code. However, methods to paint an image depends on some 'pipe' classes which are not available. Although you do stuff with classloading, you will probably hit some native, optimized class which cannot be manipulated to do the theoretically optimal approach; all you get is image painting as squares.
However we can make an approach in which our own, non-native (read:slow?), code runs as little as possible, and not depending on the image size but rather the (relatively) low area in the round rect. Also, without copying the images in memory, consuming a lot of memory. But if you have a lot of memory, then obviously, a cached image is faster after the instance has been created.
Alternative 1:
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import javax.swing.JLabel;
public class TPanel2 extends JLabel implements Composite, CompositeContext {
private int w = 300;
private int h = 200;
private int cornerRadius = 20;
private int[] roundRect; // first quadrant
private BufferedImage image;
private int[][] first = new int[cornerRadius][];
private int[][] second = new int[cornerRadius][];
private int[][] third = new int[cornerRadius][];
private int[][] forth = new int[cornerRadius][];
public TPanel2() {
setOpaque(false);
setPreferredSize(new Dimension(w, h));
setMaximumSize(new Dimension(w, h));
setMinimumSize(new Dimension(w, h));
// calculate round rect
roundRect = new int[cornerRadius];
for(int i = 0; i < roundRect.length; i++) {
roundRect[i] = (int)(Math.cos(Math.asin(1 - ((double)i)/20))*20); // x for y
}
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); // all black
}
#Override
public void paintComponent(Graphics g) {
// discussion:
// We have to work with the passed Graphics object.
if(g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g;
// draw the whole image and save the corners
g2d.setComposite(this);
g2d.drawImage(image, 0, 0, null);
} else {
super.paintComponent(g);
}
}
#Override
public CompositeContext createContext(ColorModel srcColorModel,
ColorModel dstColorModel, RenderingHints hints) {
return this;
}
#Override
public void dispose() {
}
#Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
// lets assume image pixels >> round rect pixels
// lets also assume bulk operations are optimized
// copy current pixels
for(int i = 0; i < cornerRadius; i++) {
// quadrants
// from top to buttom
// first
first[i] = (int[]) dstOut.getDataElements(src.getWidth() - (cornerRadius - roundRect[i]), i, cornerRadius - roundRect[i], 1, first[i]);
// second
second[i] = (int[]) dstOut.getDataElements(0, i, cornerRadius - roundRect[i], 1, second[i]);
// from buttom to top
// third
third[i] = (int[]) dstOut.getDataElements(0, src.getHeight() - i - 1, cornerRadius - roundRect[i], 1, third[i]);
// forth
forth[i] = (int[]) dstOut.getDataElements(src.getWidth() - cornerRadius + roundRect[i], src.getHeight() - i - 1, cornerRadius - roundRect[i], 1, forth[i]);
}
// overwrite entire image as a square
dstOut.setRect(src);
// copy previous pixels back in corners
for(int i = 0; i < cornerRadius; i++) {
// first
dstOut.setDataElements(src.getWidth() - cornerRadius + roundRect[i], i, first[i].length, 1, second[i]);
// second
dstOut.setDataElements(0, i, second[i].length, 1, second[i]);
// third
dstOut.setDataElements(0, src.getHeight() - i - 1, third[i].length, 1, third[i]);
// forth
dstOut.setDataElements(src.getWidth() - cornerRadius + roundRect[i], src.getHeight() - i - 1, forth[i].length, 1, forth[i]);
}
}
}
Alternative 2:
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import javax.swing.JLabel;
public class TPanel extends JLabel implements Composite, CompositeContext {
private int w = 300;
private int h = 200;
private int cornerRadius = 20;
private int[] roundRect; // first quadrant
private BufferedImage image;
private boolean initialized = false;
private int[][] first = new int[cornerRadius][];
private int[][] second = new int[cornerRadius][];
private int[][] third = new int[cornerRadius][];
private int[][] forth = new int[cornerRadius][];
public TPanel() {
setOpaque(false);
setPreferredSize(new Dimension(w, h));
setMaximumSize(new Dimension(w, h));
setMinimumSize(new Dimension(w, h));
// calculate round rect
roundRect = new int[cornerRadius];
for(int i = 0; i < roundRect.length; i++) {
roundRect[i] = (int)(Math.cos(Math.asin(1 - ((double)i)/20))*20); // x for y
}
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); // all black
}
#Override
public void paintComponent(Graphics g) {
if(g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g;
// draw 1 + 2 rectangles and copy pixels from image. could also be 1 rectangle + 4 edges
g2d.setComposite(AlphaComposite.Src);
g2d.drawImage(image, cornerRadius, 0, image.getWidth() - cornerRadius - cornerRadius, image.getHeight(), null);
g2d.drawImage(image, 0, cornerRadius, cornerRadius, image.getHeight() - cornerRadius - cornerRadius, null);
g2d.drawImage(image, image.getWidth() - cornerRadius, cornerRadius, image.getWidth(), image.getHeight() - cornerRadius, image.getWidth() - cornerRadius, cornerRadius, image.getWidth(), image.getHeight() - cornerRadius, null);
// draw the corners using our own logic
g2d.setComposite(this);
g2d.drawImage(image, 0, 0, null);
} else {
super.paintComponent(g);
}
}
#Override
public CompositeContext createContext(ColorModel srcColorModel,
ColorModel dstColorModel, RenderingHints hints) {
return this;
}
#Override
public void dispose() {
}
#Override
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
// assume only corners need painting
if(!initialized) {
// copy image pixels
for(int i = 0; i < cornerRadius; i++) {
// quadrants
// from top to buttom
// first
first[i] = (int[]) src.getDataElements(src.getWidth() - cornerRadius, i, roundRect[i], 1, first[i]);
// second
second[i] = (int[]) src.getDataElements(cornerRadius - roundRect[i], i, roundRect[i], 1, second[i]);
// from buttom to top
// third
third[i] = (int[]) src.getDataElements(cornerRadius - roundRect[i], src.getHeight() - i - 1, roundRect[i], 1, third[i]);
// forth
forth[i] = (int[]) src.getDataElements(src.getWidth() - cornerRadius, src.getHeight() - i - 1, roundRect[i], 1, forth[i]);
}
initialized = true;
}
// copy image pixels into corners
for(int i = 0; i < cornerRadius; i++) {
// first
dstOut.setDataElements(src.getWidth() - cornerRadius, i, first[i].length, 1, second[i]);
// second
dstOut.setDataElements(cornerRadius - roundRect[i], i, second[i].length, 1, second[i]);
// third
dstOut.setDataElements(cornerRadius - roundRect[i], src.getHeight() - i - 1, third[i].length, 1, third[i]);
// forth
dstOut.setDataElements(src.getWidth() - cornerRadius, src.getHeight() - i - 1, forth[i].length, 1, forth[i]);
}
}
}
Hope this helps, this is somewhat of a second-best solution but that's life (this is when some graphics-guru comes and proves me wrong (??)..) ;-)
I am trying to draw horizontal and vertical lines on a bufferedimage. It should end up looking like a grid of cells. But when I run the code, I see only two lines: the leftmost line and the topmost line (ie. a line from 0,0 to 0,height of image & 0,0 to width of image,0) Heres the code snippet:
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.BLACK);
BasicStroke bs = new BasicStroke(2);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
g2d.drawLine((imgDim.width+2)*i, 0, (imgDim.width+2)*i, imgDim.height-1);
g2d.drawLine(0, (imgDim.height+2)*i, imgDim.width-1, (imgDim.height+2)*i);
}
And the overriden paint method:
public void paint(Graphics g) {
g.drawImage(mazeImage, 0, 0, this);
}
This is all in a class called RobotMaze that extends JPanel. Any help is appreciated.
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
class GridLines {
public static void main(String[] args) {
Dimension imgDim = new Dimension(200,200);
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.BLACK);
BasicStroke bs = new BasicStroke(2);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
// unless divided by some factor, these lines were being
// drawn outside the bound of the image..
g2d.drawLine((imgDim.width+2)/20*i, 0, (imgDim.width+2)/20*i,imgDim.height-1);
g2d.drawLine(0, (imgDim.height+2)/20*i, imgDim.width-1, (imgDim.height+2)/20*i);
}
ImageIcon ii = new ImageIcon(mazeImage);
JOptionPane.showMessageDialog(null, ii);
}
}
Print out your coordinates and you will see that you are plotting points outside the width and height of the image:
System.out.printf("Vertical: (%d,%d)->(%d,%d)\n",(imgDim.width+2)*i, 0, (imgDim.width+2)*i, imgDim.height-1);
System.out.printf("Horizontal: (%d,%d)->(%d,%d)\n",0, (imgDim.height+2)*i, imgDim.width-1, (imgDim.height+2)*i);
How do you expect the result of (imgDim.width+2)*i to be within the image boundaries if i > 0?