Understanding Swing code from "Filthy Rich Clients" - java

Below is the code from "Filthy Rich Clients" by Romain Guy and Chet Haase
private class ImageViewer extends JComponent {
private BufferedImage image, landscape;
private ImageViewer() {
try {
image = ImageIO.read(new File("picture.png"));
landscape = ImageIO.read(new File("landscape.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
BufferedImage temp = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = temp.createGraphics();
if (shadow.isSelected()) {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g2.drawImage(image, x + 4, y + 10, null);
Composite oldComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.75f));
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setComposite(oldComposite);
g2.drawImage(image, x, y, null);
} else {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g2.drawImage(image, x, y, null);
Composite oldComposite = g2.getComposite();
g2.setComposite(AlphaComposite.SrcIn);
x = (getWidth() - landscape.getWidth()) / 2;
y = (getHeight() - landscape.getHeight()) / 2;
g2.drawImage(landscape, x, y, null);
g2.setComposite(oldComposite);
}
g2.dispose();
g.drawImage(temp, 0, 0, null);
}
}
It is a part of the code to obtain the following output with different states when checkbox is checked:-
What i dont understand is
1)what is the line
BufferedImage temp = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
doing there because if I write only the following code and run nothing is obtained in the output.
BufferedImage temp = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = temp.createGraphics();
if (jcb.isSelected()) {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g2.drawImage(image, x + 4, y + 10, null);
}
2)What is the need to obtain g2 after creating the 'temp' bufferedImage? Can't I do it directly like
Graphics2D g2=(Graphics2D)g.create();
3)What is practical difference between TYPE_INT_RGB and TYPE_INT_ARGB.?

This is double buffering:
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
You first draw on an off-screen image, which in this case is backed by a BufferedImage object referenced in the variable temp; then you do whatever to the off-screen image; finally, you print the result on the component, via g.drawImage(temp, ...). This is not to have the user see glitches or artifacts due to the image being constructed directly on the screen.

Related

Unable to get and set the circular Icon

I am new to programming and I've been trying to get and set the icon to circle but it's not being updated. I want to set every icon that was set to JLabel will become circular.
class CircleLabel extends JLabel {
private Icon icon;
private int borderSize;
#Override
protected void paintComponent(Graphics g) {
if (getIcon() != null) {
icon = getIcon();
int width = getWidth();
int height = getHeight();
int diameter = Math.min(width, height);
int x = width / 2 - diameter / 2;
int y = height / 2 - diameter / 2;
int border = borderSize * 2;
diameter -= border;
Dimension size = getAutoSize(icon, diameter);
BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2_img = img.createGraphics();
g2_img.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2_img.fillOval(0, 0, diameter, diameter);
Composite composite = g2_img.getComposite();
g2_img.setComposite(AlphaComposite.SrcIn);
g2_img.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2_img.drawImage(toImage(icon), 0, 0, size.width, size.height, null);
g2_img.setComposite(composite);
g2_img.dispose();
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(255, 255, 255));
diameter += border;
g2.fillOval(borderSize, borderSize, diameter, diameter);
g2.drawImage(img, x - borderSize, y + borderSize, null);
} else {
System.out.println("No Icon!");
}
super.paintComponent(g);
}
private Dimension getAutoSize(Icon image, int size) {
int w = size;
int h = size;
int iw = image.getIconWidth();
int ih = image.getIconHeight();
double xScale = (double) w / iw;
double yScale = (double) h / iw;
System.out.println(xScale);
System.out.println(yScale);
double scale = Math.max(xScale, yScale);
int width = (int) (scale * iw);
int height = (int) (scale * ih);
if (width < 1) {
width = 1;
}
if (height < 1) {
height = 1;
}
return new Dimension(width, height);
}
private Image toImage(Icon icon) {
return ((ImageIcon) icon).getImage();
}
}
If I set the icon manually and removed the icon from the label, it will work but when I add the icon to the label through properties, it will not work.
icon = new ImageIcon(getClass().getResource("/Attachments/user.png"));
I found this on YouTube and wanted to apply it to the application I'm trying to build.

I'm rotating image in java but want to save rotated image [duplicate]

This question already has answers here:
Java2D - How to rotate an image and save the result
(3 answers)
Closed 5 years ago.
I'm using AffineTransform to rotate the image and I had tried to save the rotated image by ImageIo.write it is saving the image but not the rotated image it's saving the original image. so please tell me how to correct it Thanks in advance.
This is my code for rotation and saving the image
public class Image {
public static void main(String[] args) {
new Image();
}
public Image() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private JSlider slider;
private BufferedImage image;
public TestPane() {
setLayout(new BorderLayout());
try {
File imagefile = new File("C:/pics/1206.jpg");
image = ImageIO.read(imagefile);
ImageIO.write(image, "jpg",new File("C:/pics"));
ImageIO.write(image, "bmp",new File("C:/pics"));
ImageIO.write(image, "gif",new File("C:/picsf"));
ImageIO.write(image, "png",new File("C:/pics"));
} catch (IOException ex) {
ex.printStackTrace();
}
slider = new JSlider();
slider.setMinimum(0);
slider.setMaximum(360);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(10);
slider.setValue(0);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
}
public double getAngle() {
return Math.toRadians(slider.getValue());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g2d.setColor(Color.BLACK);
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.setToRotation(getAngle(), x + (image.getWidth() / 2), y + (image.getHeight() / 2));
at.translate(x, y);
g2d.setTransform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
}
}
Let's start with, this isn't rotating the image, it's rotating the Graphics context which is used to display the image, it doesn't affect the original image at all
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
g2d.setColor(Color.BLACK);
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.setToRotation(getAngle(), x + (image.getWidth() / 2), y + (image.getHeight() / 2));
at.translate(x, y);
g2d.setTransform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
And then this...
try {
File imagefile = new File("C:/pics/1206.jpg");
image = ImageIO.read(imagefile);
ImageIO.write(image, "jpg",new File("C:/pics"));
ImageIO.write(image, "bmp",new File("C:/pics"));
ImageIO.write(image, "gif",new File("C:/picsf"));
ImageIO.write(image, "png",new File("C:/pics"));
} catch (IOException ex) {
ex.printStackTrace();
}
which just saves the original image to a number of different formats ... to the same file 😕, but doesn't even react to any changes to the angle
Instead, you need to use something which generates a new image from the original, rotated by the amount you want...
public BufferedImage rotateImageByDegrees(BufferedImage img, double degrees) {
double rads = Math.toRadians(degrees);
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = img.getWidth();
int h = img.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
int x = clickPoint == null ? w / 2 : clickPoint.x;
int y = clickPoint == null ? h / 2 : clickPoint.y;
at.rotate(rads, x, y);
g2d.setTransform(at);
g2d.drawImage(img, 0, 0, this);
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, newWidth - 1, newHeight - 1);
g2d.dispose();
return rotated;
}
Then you can save it...
File imagefile = new File("C:/pics/1206.jpg");
image = ImageIO.read(imagefile);
BufferedImage rotated = rotateImageByDegrees(image, 22.5);
ImageIO.write(rotated, "png", new File("RotatedBy225.png"));
So, the next time you use one of my previous examples and I tell you it's not doing what you think/want it to, I hope you will understand my meaning better 😉 and look more closly at the other examples we show you

Java Greyscale buffered image

So I have a byte array representing pixel data (8bit grayscale). No header. No nothing. Just the data. I want to create a buffered image from this data. I did
image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);
this.x = w;
this.y = h;
scalemode=false;
exactmode=true;
where w is just width in pixel,h is height in pixel,data is the byte array and image is BufferedImage
here is my paint method
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int rx = (this.getWidth() - x) / 2;
int ry = (this.getHeight() - y) / 2;
g2d.drawImage(image, rx, ry,x,y, null);
}
I, however, get this image (the real image is a fingerprint, which is mostly white pixel)
What went wrong? I tried saving the data as is and then viewing it in Photoshop. The data is fine.
[edit]
Never mind this problem. I fucked up in other part of the code and was not aware. Thank you for all inputs though
It's hard to know exactly what is wrong, as you haven't posted enough information. We don't know w, h or what information is in your data. We don't know what the image should look like.
However, here's some code that does pretty much exactly what you are doing, and it works for me:
// Set up h/w and backing data
int w = 300;
int h = 200;
byte[] data = new byte[w * h];
// Create a smooth gradient
for (int y = 0; y < h; y++) {
int off = y * w;
for (int x = 0; x < w; x++) {
data[off + x] = (byte) (Math.round((x / (double) w) * 127)
+ Math.round((y / (double) h) * 127));
}
}
// Create BufferedImage from data
final BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, data);
// Show it all in a window
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame(getClass().getSimpleName());
frame.add(new JLabel(new ImageIcon(image)));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
Here is the result:
draw every byte on each pixel...
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
for (int dy = 0; dy < h; dy ++){
for(int dx = 0; dx < w; dx ++){
int index = dy*w + dx;
int rgb = data[index];
rgb = rgb << 24 & 0xFFFF; //BufferedImage.TYPE_BYTE_GRAY consideres only the red-channel;
//rgb = 00 data[index] FF FF
image.setRGB(dx,dy,rgb);
}
}
}
you didn't set up your Buffer properly...
byte[] data = ...
DataBufferByte db = new DataBufferByte(data, w*h);
image.getRaster().setDataElements(0, 0, w, h, db );
see http://docs.oracle.com/javase/7/docs/api/java/awt/image/WritableRaster.html#setDataElements%28int,%20int,%20java.lang.Object%29

Save JPanel as Image HD Quality

I am trying to save a JPanel as Image (Png, Jpg, whatever) but with Graphics2D the Quality is very low. My JPanel contains mostly text and I want to print the panel 4 times on a A4 paper size, so that it fills the page.
But the text is like washed-out when i print the image. I tried to create an A3 image then print it to the smaller A4 size. The quality increases very little, almost insignificantly.
Here is the function i use to generate the image, based on this ScreenImage.Class i found here :
public void exportToPNG(JRootPane panel){
Dimension size = panel.getSize();
BufferedImage image = new BufferedImage(
size.width, size.height * 4 /* use the same image 4 times */
, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.drawImage(ScreenImage.createImage(panel), 0, 0, size.width, size.height, null);
g2.drawImage(ScreenImage.createImage(panel), 0, size.height, size.width, size.height, null);
g2.drawImage(ScreenImage.createImage(panel), 0, size.height * 2, size.width, size.height, null);
g2.drawImage(ScreenImage.createImage(panel), 0, size.height * 3, size.width, size.height, null);
try{
ImageIO.write(image, "png", new File("D:\\test-image.png"));
}
catch(Exception e)
{
e.printStackTrace();
}
}
Here is a sample image i generated:
click the link..
You should see that washed-out effect on the image even when zooming-in a little.
Is there a way to increase the quality? or a dedicated library?
Let's start with the obvious...
A A4 sheet of paper is 21.0cm x 29.7cm.
At 300dpi, that makes it 2480.315x3507.874 pixels
At 72dpi, that makes it 595.2756x841.8898 pixels
Why's this important? Java renders to the screen at 72dpi, but is capable of printing at 300dpi (above and below, but this is nice figure). This means, roughly, you'd to scale the screen image UP by 4 times. Up scaling is never pleasant, as demonstrated here
A better solution would be work with the printer DPI and scale the image down to the screen.
For convenience sake, you can use something like...
public static final float CM_PER_INCH = 0.393700787f;
public static float cmsToPixel(float cms, float dpi) {
return cmToInches(cms) * dpi;
}
public static float cmToInches(float cms) {
return cms * CM_PER_INCH;
}
To convert from cm's to pixels at a given DPI.
Now to the fun part. You "could" use Swing components to render the basic layout, it might be easier, but you'd have to scale the graphics down, as the core printer API assumes a DPI of 72 (don't ask). Now scaling down generally results in a better output, but there is another solution.
Instead, you could use the Graphics 2D API and generate the output yourself...
public static class Ticket {
public enum TextAlignment {
LEFT,
RIGHT,
CENTRE
}
protected static final int STUB_NUMBER_Y_POS = 12;
private Font plainFont;
private Font boldFont;
private Stroke dashedStroke;
public void paint(Graphics2D g2d, double pageWidth, double pageHeight, int stubNumber) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
paintLeftStub((Graphics2D) g2d.create(), pageWidth, pageHeight, stubNumber);
paintBody((Graphics2D) g2d.create(), pageWidth, pageHeight, stubNumber);
paintRightStub((Graphics2D) g2d.create(), pageWidth, pageHeight, stubNumber);
paintEndStub((Graphics2D) g2d.create(), pageWidth, pageHeight, stubNumber);
g2d = (Graphics2D) g2d.create();
g2d.setColor(Color.GRAY);
g2d.setStroke(getDashedStroke());
g2d.draw(new Line2D.Double(0, pageHeight - 1, pageWidth, pageHeight - 1));
g2d.dispose();
}
protected void paintLeftStub(Graphics2D graphics, double pageWidth, double pageHeight, int stubNumber) {
graphics.setColor(Color.BLACK);
double stubWidth = pageWidth / 4;
Graphics2D g2d = (Graphics2D) graphics.create();
Font font = getBoldFont().deriveFont(18f);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
// Did mention I hate doing inline transformations :P
g2d.rotate(Math.toRadians(-90), stubWidth / 2, pageHeight / 2);
g2d.translate(0, -((stubWidth - pageHeight) / 2));
String lines[] = {"MORATUFIESTA", "", "Sat. 3 Auguest 2015", "Adult - $3"};
double x = 2;
double y = 0;
double maxWidth = 0;
for (String text : lines) {
x = calculateHorizontalCenterPositionFor(text, fm, stubWidth);
maxWidth = Math.max(maxWidth, fm.stringWidth(text));
g2d.drawString(text, (int) Math.round(x), (int) Math.round(y + fm.getAscent()));
y += fm.getHeight();
}
double blockWidth = y;
// Easier then trying to undo the transformation...
g2d.dispose();
g2d = (Graphics2D) graphics.create();
String text = "Low";
font = getPlainFont().deriveFont(6f);
g2d.setFont(font);
fm = g2d.getFontMetrics();
double xPos = calculateHorizontalCenterPositionFor(text, fm, blockWidth) + 2;
double yPos = (pageHeight - maxWidth) / 2;
g2d.drawString(text, (int) Math.round(xPos), (int) Math.round(yPos - fm.getAscent()));
g2d.setStroke(getDashedStroke());
g2d.draw(new Line2D.Double(stubWidth, 0, stubWidth, pageHeight));
g2d.dispose();
g2d = (Graphics2D) graphics.create();
drawStubNumber(g2d, stubWidth - 8 - fm.getHeight() - fm.getAscent(), STUB_NUMBER_Y_POS, stubNumber);
g2d.dispose();
}
protected Stroke getDashedStroke() {
if (dashedStroke == null) {
float dash[] = {10.0f};
dashedStroke = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10f, dash, 0.0f);
}
return dashedStroke;
}
public Font getPlainFont() {
if (plainFont == null) {
plainFont = UIManager.getFont("Label.font");
}
return plainFont;
}
public Font getBoldFont() {
if (boldFont == null) {
boldFont = getPlainFont();
boldFont = boldFont.deriveFont(Font.BOLD);
}
return boldFont;
}
protected double calculateHorizontalCenterPositionFor(String text, FontMetrics fm, double width) {
return (width - fm.stringWidth(text)) / 2d;
}
protected void paintBody(Graphics2D graphics, double pageWidth, double pageHeight, int stubNumber) {
int padding = 8;
double xOffset = pageWidth / 4d;
graphics.setColor(Color.BLACK);
double bodyWidth = (pageWidth / 2d);
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
g2d.setFont(getPlainFont().deriveFont(12f));
FontMetrics fm = g2d.getFontMetrics();
String text = "Moratu Fiesta";
double xPos = bodyWidth - fm.stringWidth(text) - padding;
double yPos = padding;
g2d.drawString(text, (int) Math.round(xPos), (int) Math.round(yPos + fm.getAscent()));
g2d.dispose();
Font plainFont = getPlainFont().deriveFont(9.5f);
TextLine[] addressLines01 = new TextLine[]{
new TextLine("61 Railway Pde North", plainFont),
new TextLine("Glen Waverley", plainFont),
new TextLine("03 9836 8673", plainFont)
};
TextLine[] addressLines02 = new TextLine[]{
new TextLine("1120, Glen Huntly", plainFont),
new TextLine("Glen Huntly", plainFont),
new TextLine("03 9571 5544", plainFont)
};
TextLine[] sponsorLines = new TextLine[]{
new TextLine("Proudly supported by", plainFont),
new TextLine("Quality Groceries", plainFont.deriveFont(Font.BOLD)),
new TextLine("Visit for all your grocery needs", plainFont)
};
Area area = new Area();
addTo(g2d, area, addressLines01);
addTo(g2d, area, addressLines02);
addTo(g2d, area, sponsorLines);
int height = area.getBounds().height;
double bottomBlockYPos = pageHeight - height - padding;
g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
drawTextLines(g2d, padding, bottomBlockYPos, bodyWidth - (padding * 2), TextAlignment.LEFT, addressLines01);
drawTextLines(g2d, padding, bottomBlockYPos, bodyWidth - (padding * 2), TextAlignment.CENTRE, sponsorLines);
drawTextLines(g2d, padding, bottomBlockYPos, bodyWidth - (padding * 2), TextAlignment.RIGHT, addressLines02);
g2d.dispose();
plainFont = getPlainFont().deriveFont(10f);
TextLine[] textLines = new TextLine[]{
new TextLine("On Saturday, August 3, 2013 from 6.30pm till midnight", plainFont.deriveFont(Font.BOLD)),
new TextLine("At 21, Sacred Heart Parish Hall, Johnson Street, Oakleigh", plainFont)
};
int blockHeight = getSizeFor(g2d, textLines).height;
double mainBlockYPos = (pageHeight - blockHeight) / 2;
g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
drawTextLines(g2d, 0, mainBlockYPos, bodyWidth, TextAlignment.CENTRE, textLines);
g2d.dispose();
g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
Font boldFont = getBoldFont().deriveFont(9f);
double upperYPos = (mainBlockYPos + blockHeight);
double middleBlockYPos = upperYPos + ((bottomBlockYPos - upperYPos) / 2) - (g2d.getFontMetrics(boldFont).getHeight() / 2);
drawTextLines(g2d, padding, middleBlockYPos, bodyWidth - (padding * 2), TextAlignment.LEFT, new TextLine("Melway Ref, 69 FB", boldFont));
drawTextLines(g2d, padding, middleBlockYPos, bodyWidth - (padding * 2), TextAlignment.CENTRE, new TextLine("Music by REDEMPTION", boldFont));
drawTextLines(g2d, padding, middleBlockYPos, bodyWidth - (padding * 2), TextAlignment.RIGHT, new TextLine("Donations $30", boldFont));
g2d.dispose();
g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
g2d.setStroke(getDashedStroke());
g2d.draw(new Line2D.Double(bodyWidth, 0, bodyWidth, pageHeight));
g2d.dispose();
g2d = (Graphics2D) graphics.create();
drawStubNumber(g2d, padding + xOffset, STUB_NUMBER_Y_POS, stubNumber);
g2d.dispose();
}
protected void drawStubNumber(Graphics2D g2d, double x, double y, int stubNumber) {
Font font = getBoldFont().deriveFont(18f);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(stubNumber);
g2d.translate(x, y);
g2d.rotate(Math.toRadians(-90), fm.stringWidth(text) / 2, fm.getHeight() / 2);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
}
protected void paintRightStub(Graphics2D graphics, double pageWidth, double pageHeight, int stubNumber) {
graphics.setColor(Color.BLACK);
int padding = 8;
double xOffset = (pageWidth / 4d) * 3;
double stubWidth = (pageWidth / 4d) / 2;
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
g2d.setStroke(getDashedStroke());
g2d.draw(new Line2D.Double(stubWidth, 0, stubWidth, pageHeight));
g2d.dispose();
g2d = (Graphics2D) graphics.create();
drawStubNumber(g2d, padding + xOffset, STUB_NUMBER_Y_POS, stubNumber);
g2d.dispose();
g2d = (Graphics2D) graphics.create();
String text = "Cafe Little Hut";
Font font = getPlainFont().deriveFont(23f);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
double x = xOffset + ((stubWidth - fm.stringWidth(text)) / 2d);
double y = ((pageHeight - fm.getHeight()) / 2d);
g2d.translate(x, y);
g2d.rotate(Math.toRadians(-90), fm.stringWidth(text) / 2, fm.getHeight() / 2);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
}
protected void paintEndStub(Graphics2D graphics, double pageWidth, double pageHeight, int stubNumber) {
graphics.setColor(Color.BLACK);
int padding = 8;
double stubWidth = (pageWidth / 4d) / 2;
double xOffset = ((pageWidth / 4d) * 3 + stubWidth);
Graphics2D g2d = (Graphics2D) graphics.create();
g2d.translate(xOffset, 0);
g2d.setStroke(getDashedStroke());
g2d.draw(new Line2D.Double(stubWidth, 0, stubWidth, pageHeight));
g2d.dispose();
g2d = (Graphics2D) graphics.create();
drawStubNumber(g2d, padding + xOffset, STUB_NUMBER_Y_POS, stubNumber);
g2d.dispose();
g2d = (Graphics2D) graphics.create();
String text = "Entrance";
Font font = getBoldFont().deriveFont(32f);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
double x = xOffset + ((stubWidth - fm.stringWidth(text)) / 2);
double y = ((pageHeight - fm.getHeight()) / 2);
g2d.translate(x, y);
g2d.rotate(Math.toRadians(-90), fm.stringWidth(text) / 2, fm.getHeight() / 2);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
}
protected Dimension drawTextLines(Graphics2D g2d, double xPos, double yPos, double width, TextAlignment textAlignment, TextLine... textLines) {
Area area = new Area();
for (TextLine textLine : textLines) {
g2d.translate(xPos, yPos);
Dimension size = textLine.getBounds(g2d);
textLine.paint(g2d, width, textAlignment);
area.add(new Area(new Rectangle2D.Double(xPos, yPos, size.width, size.height)));
g2d.translate(-xPos, -yPos);
yPos += size.height;
}
return area.getBounds().getSize();
}
protected void addTo(Graphics2D g2d, Area area, TextLine... textLines) {
area.add(new Area(new Rectangle(getSizeFor(g2d, textLines))));
}
protected Dimension getSizeFor(Graphics2D g2d, TextLine... textLines) {
int yPos = 0;
int width = 0;
for (TextLine textLine : textLines) {
Dimension size = textLine.getBounds(g2d);
yPos += size.height;
width = Math.max(size.width, width);
}
return new Dimension(width, yPos);
}
protected class TextLine {
private String text;
private Font font;
public TextLine(String text, Font font) {
this.text = text;
this.font = font;
}
public String getText() {
return text;
}
public Font getFont() {
return font;
}
public Dimension getBounds(Graphics2D g2d) {
FontMetrics fm = g2d.getFontMetrics(getFont());
return new Dimension(fm.stringWidth(text), fm.getHeight());
}
public void paint(Graphics2D g2d, double width, TextAlignment textAlignment) {
Dimension bounds = getBounds(g2d);
FontMetrics fm = g2d.getFontMetrics(getFont());
g2d.setFont(font);
double x = 0;
switch (textAlignment) {
case CENTRE:
x = (width - bounds.width) / 2;
break;
case RIGHT:
x = width - bounds.width;
break;
}
g2d.drawString(getText(), (int) Math.round(x), fm.getAscent());
}
}
}
Why would you do that? It's easier to wrap a Printable around and print to a printer and you can also "paint" to a component (or image)
For example...
public class TicketPrintable implements Printable {
private Ticket ticket;
public TicketPrintable(Ticket ticket) {
this.ticket = ticket;
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
int result = NO_SUCH_PAGE;
if (pageIndex == 0) {
Graphics2D g2d = (Graphics2D) graphics;
double width = pageFormat.getImageableWidth();
double height = pageFormat.getImageableHeight();
g2d.translate((int) pageFormat.getImageableX(),
(int) pageFormat.getImageableY());
double ticketHeight = height / 4d;
for (int index = 0; index < 4; index++) {
ticket.paint(g2d, width, ticketHeight, index + 1);
g2d.translate(0, ticketHeight);
}
result = PAGE_EXISTS;
}
return result;
}
}
And to print it, you would use something like...
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(MediaSizeName.ISO_A4);
aset.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
aset.add(new MediaPrintableArea(0, 0, 210, 297, MediaPrintableArea.MM));
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(new TicketPrintable(new Ticket()));
if (pj.printDialog(aset)) {
try {
pj.print(aset);
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
On the screen it looks like...
On paper it looks like (scaled down for SO)
Now having said that, I would strongly encourage you to learn JasperReports, which makes this all so much simpler...
Updated
So, I was sitting in traffic and thought to myself, I wonder if I can just use scaling to render the Ticket to an image, so I thought I'd give it a try...
The top image is 72dpi, the bottom image is scaled to 300dpi
double pageWidth = cmsToPixel(21.0f, 300f);
double pageHeight = cmsToPixel(29.7f, 300f);
double imageWidth = cmsToPixel(21.0f, 72f);
double imageHeight = cmsToPixel(29.7f, 72f);
double scaleFactor = ImageUtilities.getScaleFactorToFit(
new Dimension((int) Math.round(imageWidth), (int) Math.round(imageHeight)),
new Dimension((int) Math.round(pageWidth), (int) Math.round(pageHeight)));
int width = (int) Math.round(pageWidth);
int height = (int) Math.round(pageHeight);
BufferedImage img = new BufferedImage(
width,
height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
g2d.scale(scaleFactor, scaleFactor);
Ticket ticket = new Ticket();
ticket.paint(g2d, img.getWidth() / scaleFactor, (img.getHeight() / scaleFactor) / 4, 1);
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Ticket.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
Scale factor algorithms
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = 1;
if (iMasterSize > iTargetSize) {
dScale = (double) iTargetSize / (double) iMasterSize;
} else {
dScale = (double) iTargetSize / (double) iMasterSize;
}
return dScale;
}
Note: This is only really going to work for text and primitive graphics, you put an image into this and it won't work, the image will be scaled up and look crappy, use demonstrated in the linked answer from before. In that case, you'd have to design the form to render at 300+dpi and scale the image down to 72dpi

Java 2d rotation in direction mouse point

So far I have a java app where I draw a circle(player) and then draw a green rectangle on top(gun barrel). I have it so when the player moves, the barrel follows with it. I want it to find where the mouse is pointing and then rotate the barrel accordingly. For an example of what I mean look at this video I found http://www.youtube.com/watch?v=8W7WSkQq5SU See how the player image reacts when he moves the mouse around?
Here's an image of what the game looks like so far:
So how do I rotate it like this? Btw I don't like using affinetransform or Graphics2D rotation. I was hoping for a better way. Thanks
Using the Graphics2D rotation method is indeed the easiest way. Here's a simple implementation:
int centerX = width / 2;
int centerY = height / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
g.fillRect(...); // draw your rectangle
If you want to remove the rotation when you're done so you can continue drawing normally, use:
Graphics2D g2d = (Graphics2D)g;
AffineTransform transform = g2d.getTransform();
g2d.rotate(angle, centerX, centerY);
g2d.fillRect(...); // draw your rectangle
g2d.setTransform(transform);
It's a good idea to just use Graphics2D anyway for anti-aliasing, etc.
Using AffineTransform, sorry, only way I know how :P
public class RotatePane extends javax.swing.JPanel {
private BufferedImage img;
private Point mousePoint;
/**
* Creates new form RotatePane
*/
public RotatePane() {
try {
img = ImageIO.read(getClass().getResource("/MT02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
int x = (width - img.getWidth()) / 2;
int y = (height - img.getHeight()) / 2;
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
g2d.drawImage(img, x, y, this);
x = width / 2;
y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
g2d.dispose();
}
}
Will produce this effect
The red line (point out from the center) will want to follow the cursor.

Categories

Resources