i have design a jpanel with so many swing components with scrollable capability. i want to export whole Jpanle into pdf file.but i am not able to export whole Jpanle.
I have use itext for pdf generation.
My problem is that i am not able to export whole jpanel into pdf. When i export half of Jpanel
components export.but half portion do not export.
this is my code.
public void PrintFrameToPDF(JPanel c, File file) {
try {
Document d = new Document();
PdfWriter writer = PdfWriter.getInstance(d, new FileOutputStream("F://newfile.pdf"));
d.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate template = cb.createTemplate(800, 1600);
Graphics2D g2d = template.createGraphics(800, 1600);
// g2d.translate(1.0, 1.0);
c.paintAll(g2d);
// c.addNotify();
// c.validate();
g2d.dispose();
cb.addTemplate(template, 0, 0);
d.close();
} catch (Exception e) {
//
}
}
plz help me .
tnx
Consider creating a java.awt.Image from the panel first (by painting the panel to an Image). You can then get an instance of com.itextpdf.text.Image using:
com.itextpdf.text.Image.getInstance(PdfWriter writer,
java.awt.Image awtImage,
float quality) -
Gets an instance of a com.itextpdf.textImage from a java.awt.Image. The image is added as a JPEG with a user defined quality.
Then you can scale the image with the com.itextpdf.text.Image API methods scaleToFit or scalePercent() (as used in the example below). More information on using images (in iText) can be found here
The following program create a panel of size 2000x2000 in which squares 20x20 (of 100px each) are drawn onto a panel. The panel is contained inside a scroll pane. It is then painted on to an image, where the image will be scaled and added to the pdf document and printed to pdf.
The below image just shows how the entire panel is drawn onto the image then another panel is created, using the previous panel image, to draw onto the the new panel. The new panel is then shown via a dialog.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfWriter;
/**
* This example requires iText. I retrieved it from Maven repository
*
* <dependency>
* <groupId>com.itextpdf</groupId>
* <artifactId>itextpdf</artifactId>
* <version>5.5.2</version>
* </dependency>
*
* The program can be run without iText if you comment out the entire
* method printToPDF (and iText imports), along with it's method call in
* the class constructor. The result will be the the image above.
*/
public class LargePanelToImageMCVE {
public LargePanelToImageMCVE() {
LargeImagePanel panel = new LargeImagePanel();
JFrame frame = new JFrame();
frame.add(new JScrollPane(panel));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
final java.awt.Image image = getImageFromPanel(panel);
/* This was just a text panel to make sure the full panel was
* drawn to the panel.
*/
JPanel newPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
/* Print Image to PDF */
String fileName = "D://newfile.pdf";
printToPDF(image, fileName);
/* This was just a test to show the newPanel drew the entire
* original panel (scaled)
*/
JOptionPane.showMessageDialog(null, newPanel);
}
public void printToPDF(java.awt.Image awtImage, String fileName) {
try {
Document d = new Document();
PdfWriter writer = PdfWriter.getInstance(d, new FileOutputStream(
fileName));
d.open();
Image iTextImage = Image.getInstance(writer, awtImage, 1);
iTextImage.setAbsolutePosition(50, 50);
iTextImage.scalePercent(25);
d.add(iTextImage);
d.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static java.awt.Image getImageFromPanel(Component component) {
BufferedImage image = new BufferedImage(component.getWidth(),
component.getHeight(), BufferedImage.TYPE_INT_RGB);
component.paint(image.getGraphics());
return image;
}
/**
* Demo panel that is 2000x2000 px with alternating squares
* to check all squares are drawn to image
*/
public class LargeImagePanel extends JPanel {
private static final int FULL_SIZE = 2000;
private static final int PER_ROW_COLUMN = 20;
private static final int SQUARE_SIZE = FULL_SIZE / PER_ROW_COLUMN;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < PER_ROW_COLUMN; row++) {
for (int col = 0; col < PER_ROW_COLUMN; col++) {
if ((row % 2) == (col % 2)) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(col * SQUARE_SIZE, row * SQUARE_SIZE,
SQUARE_SIZE, SQUARE_SIZE);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(FULL_SIZE, FULL_SIZE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new LargePanelToImageMCVE();
}
});
}
}
Related
is it possible to display two pictures, next to each other with BufferedImage and Graphics2D ? or should I do it with other method ?
In my code below, I was able to display two images, but the picture 1 overlaps to the picture 2.
package zdjecie;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class ObrazPanel extends JPanel {
private BufferedImage image;
private BufferedImage image2;
public ObrazPanel() {
super();
File imageFile = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java.jpg");
File imageFile2 = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java2.jpg");
try {
image = ImageIO.read(imageFile);
image2 = ImageIO.read(imageFile2);
} catch (IOException e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension);
Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
setPreferredSize(dimension2);
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, 200, 200, this);
}
}
You call setPreferredSize twice, which results in the first call doing basically nothing. That means you always have a preferredSize equal to the dimensions of the second image. What you should do is to set the size to new Dimension(image.getWidth() + image2.getWidth(), image2.getHeight()) assuming both have the same height. If that is not the case set the height as the maximum of both images.
Secondly you need to offset the second image from the first image exactly by the width of the first image:
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, image.getWidth(), 0, this);
The logic of the math was incorrect. See the getPreferredSize() method for the correct way to calculate the required width, and the changes to the paintComponent(Graphics) method to place them side-by-side.
An alternative (not examined in this answer) is to put each image into a JLabel, then add the labels to a panel with an appropriate layout.
This is the effect of the changes:
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.net.*;
import javax.imageio.ImageIO;
public class ObrazPanel extends JPanel {
private BufferedImage image;
private BufferedImage image2;
public ObrazPanel() throws MalformedURLException {
super();
URL imageFile = new URL("https://i.stack.imgur.com/7bI1Y.jpg");
URL imageFile2 = new URL("https://i.stack.imgur.com/aH5zB.jpg");
try {
image = ImageIO.read(imageFile);
image2 = ImageIO.read(imageFile2);
} catch (Exception e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
int w = image.getWidth() + image2.getWidth();
int h1 = image.getHeight();
int h2 = image2.getHeight();
int h = h1>h2 ? h1 : h2;
return new Dimension(w,h);
}
#Override
public void paintComponent(Graphics g) {
// always best to start with this..
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, image.getWidth(), 0, this);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ObrazPanel o;
try {
o = new ObrazPanel();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o);
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
};
SwingUtilities.invokeLater(r);
}
}
I would join the images whenever something changes and draw them to another buffered image. Then I can just redraw the combined image whenever the panel needs to be redrawn.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SideBySideImagePanel extends JPanel {
private static final long serialVersionUID = 5868633578732134172L;
private BufferedImage left;
private BufferedImage right;
private BufferedImage join;
public SideBySideImagePanel() {
ClassLoader loader = this.getClass().getClassLoader();
BufferedImage left = null, right = null;
try {
left = ImageIO.read(loader.getResourceAsStream("resources/Android.png"));
right = ImageIO.read(loader.getResourceAsStream("resources/Java.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.setLeft(left);
this.setRight(right);
}
public BufferedImage getLeft() {
return left;
}
public void setLeft(BufferedImage left) {
this.left = left;
}
public BufferedImage getRight() {
return right;
}
public void setRight(BufferedImage right) {
this.right = right;
}
#Override
public void invalidate() {
super.invalidate();
join = combineImages(left, right);
setPreferredSize(new Dimension(join.getWidth(), join.getHeight()));
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(join, 0, 0, null);
}
private BufferedImage combineImages(BufferedImage left, BufferedImage right) {
int width = left.getWidth() + right.getWidth();
int height = Math.max(left.getHeight(), right.getHeight());
BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics g = combined.getGraphics();
g.drawImage(left, 0, 0, null);
g.drawImage(right, left.getWidth(), 0, null);
return combined;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Image Joiner");
SideBySideImagePanel panel = new SideBySideImagePanel();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
}
I found some errors in your code and I did not got what are you trying to do...
1] Over there you are actually not using the first setup
Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension); //not used
Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
setPreferredSize(dimension2); //because overridden by this
It means, panel is having dimensions same as the image2, you should to set it as follows:
height as max of the heights of both images
width at least as summarize of widths of both pictures (if you want to paint them in same panel, as you are trying)
2] what is the image and image2 datatypes? in the block above you have File but with different naming variables, File class ofcourse dont have width or height argument
I am assuming its Image due usage in Graphics.drawImage, then:
You need to setup preferred size as I mentioned:
height to max value of height from images
width at least as summarize value of each widths
Dimensions things:
Dimension panelDim = new Dimension(image.getWidth() + image2.getWidth(),Math.max(image.getHeight(),image2.getHeight()));
setPreferredSize(panelDim)
Then you can draw images in the original size
- due coordinates are having 0;0 in the left top corner and right bottom is this.getWidth(); this.getHeight()
- check eg. this explanation
- you need to start paint in the left bottom corner and then move to correct position increase "X" as the width of first image
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
/* public abstract boolean drawImage(Image img,
int x,
int y,
Color bgcolor,
ImageObserver observer)
*/
//start to paint at [0;0]
g2d.drawImage(image, 0, 0, this);
//start to paint just on the right side of first image (offset equals to width of first picture)- next pixel on the same line, on the bottom of the screen
g2d.drawImage(image2,image2.getWidth()+1, 0, this);
}
I didn't had a chance to test it, but it should be like this.
Important things are
you need to have proper dimensions for fitting both images
screen coordinates starts in the left top corner of the screens [0;0]
I am using PotraceJ (potrace library's java version) - note that potrace is used for vectorization of images.
Situation - potrace traces image, and stores the result in a BufferedImage, which is then displayed in a JPanel as an ImageIcon.
My problem - I want to save this BufferedImage instead as a file say vector.svg
Using ImageIO.write() I tried but no file is created when I do that. Possible reason could be Java's image writers may not write svg
I have to store this vectorized image as an svg file. How should I do that?
The code that mainly vectorzies a raster image is embeded here. While you can find the whole library here at github.
package potracej.src;
import potracej.src.compat.ConvertToJavaCurves;
import potracej.src.compat.PathElement;
import potracej.src.potracej.Bitmap;
import potracej.src.potracej.PoTraceJ;
import potracej.src.potracej.param_t;
import potracej.src.potracej.path_t;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.metal.MetalButtonUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
/**
* Created with IntelliJ IDEA.
* User: san
* Date: 6/10/12
* Time: 12:55 PM
* To change this template use File | Settings | File Templates.
*/
public class Main {
static BufferedImage result;
static Bitmap bmp;
static param_t param = new param_t();
static double scale = 1;
static ImageIcon resultIcon;
static ImageIcon srcIcon;
static BufferedImage sourceImage;
static boolean renderSourceImage = false;
public static void main(String[] args) throws IOException {
Path p = Paths.get(new File(".").getCanonicalPath()+"/potracej/girl.png");
sourceImage = ImageIO.read(p.toFile());
//Toolkit.getDefaultToolkit().
WritableRaster raster = sourceImage.getRaster();
int[] iarr = new int[4];
bmp = new Bitmap((int)(sourceImage.getWidth()), (int)(sourceImage.getHeight()));
for(int y=0; y<sourceImage.getHeight(); y++) {
for(int x=0; x<sourceImage.getWidth(); x++) {
int[] pixel = raster.getPixel(x, y, iarr);
if (pixel[0] + pixel[1] + pixel[2] + pixel[3] != 0) {
bmp.put(x, y, 1);
}
}
}
BufferedImage d2 = new BufferedImage((int) (scale * sourceImage.getWidth()), (int)(scale * sourceImage.getHeight()), BufferedImage.TYPE_INT_ARGB);
Graphics2D d2g = (Graphics2D) d2.getGraphics();
d2g.scale(scale, scale);
d2g.drawImage(sourceImage, 0, 0, null);
d2g.dispose();
sourceImage.flush();
srcIcon = new ImageIcon(d2);
doTrace(scale);
JFrame frame = new JFrame("Result") {
{
setLayout(new BorderLayout());
resultIcon = new ImageIcon(result, "Result");
JButton resultButton = new JButton(resultIcon);
resultButton.setUI(new MetalButtonUI() {
#Override
protected void paintButtonPressed(Graphics g, AbstractButton b) {
//
}
});
add(resultButton, BorderLayout.CENTER);
resultButton.setPressedIcon(srcIcon);
JPanel stuff = new JPanel();
add(stuff, BorderLayout.NORTH);
stuff.setLayout(new GridLayout(4, 2));
stuff.add(new JLabel("Suppress speckles"));
final JSlider turdSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, param.turdsize);
stuff.add(turdSlider);
turdSlider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
param.turdsize = turdSlider.getValue();
doRetrace();
}
});
stuff.add(new JLabel("Smooth corners"));
final JSlider smoothSlider = new JSlider(JSlider.HORIZONTAL, 0, 300, (int) (param.opttolerance * 100));
stuff.add(smoothSlider);
smoothSlider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
param.opttolerance = smoothSlider.getValue() / 100.0;
doRetrace();
}
});
stuff.add(new JLabel("Optimize paths"));
final JSlider optSlider = new JSlider(JSlider.HORIZONTAL, 0, 125, (int) (param.alphamax * 100));
stuff.add(optSlider);
optSlider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
param.alphamax = optSlider.getValue()/100.0;
doRetrace();
}
});
final JCheckBox renderSource = new JCheckBox("Render source");
stuff.add(renderSource);
renderSource.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
renderSourceImage = renderSource.getModel().isArmed();
doRetrace();
}
});
}
private void doRetrace() {
doTrace(scale);
resultIcon.setImage(result);
repaint();
}
};
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static void doTrace(double scale) {
PoTraceJ poTraceJ = new PoTraceJ(param);
long l = System.currentTimeMillis();
path_t trace = null;
for(int i=0; i<10; i++) {
trace = poTraceJ.trace(bmp);
Thread.yield();
}
poTraceJ.resetTimers();
for(int i=0; i<100; i++) {
trace = poTraceJ.trace(bmp);
}
poTraceJ.printTimers();
l = System.currentTimeMillis() - l;
System.out.println("L="+l);
ArrayList<PathElement> al = new ArrayList<PathElement>();
ConvertToJavaCurves.convert(trace, new HashSet<ConvertToJavaCurves.Point>(), al);
if (result != null)
result.flush();
result = new BufferedImage((int)(scale * bmp.getWidth()), (int)(scale * bmp.getHeight()), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D)result.getGraphics();
g2.scale(scale, scale);
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, bmp.getWidth(), bmp.getHeight());
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
GeneralPath path = new GeneralPath();
for (PathElement pathElement : al) {
switch (pathElement.getType()) {
case CLOSE_PATH:
path.closePath();
break;
case LINE_TO:
path.lineTo(pathElement.getP0x(), pathElement.getP0y());
break;
case MOVE_TO:
path.moveTo(pathElement.getP0x(), pathElement.getP0y());
break;
case CURVE_TO:
path.curveTo(pathElement.getP0x(), pathElement.getP0y(), pathElement.getP1x(), pathElement.getP1y(), pathElement.getP2x(), pathElement.getP2y());
break;
}
}
g2.setPaint(Color.black);
g2.fill(path);
}
}
Thanks in advance.
We can convert this object:
GeneralPath path = new GeneralPath();
to SVGPath using Apache Batik
Add dependencies into pom.xml
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svggen</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-anim</artifactId>
<version>1.9</version>
</dependency>
Create methods:
private static SVGOMDocument createSvgDocument(int width, int height) {
DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
SVGOMDocument document = (SVGOMDocument) domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
Element svgTag = document.getRootElement();
svgTag.setAttribute("width", String.valueOf(width));
svgTag.setAttribute("height", String.valueOf(height));
return document;
}
private static void putPathToSvgDocument(SVGOMDocument document, GeneralPath path) {
SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
SVGPath svgPath = new SVGPath(ctx);
Element svgElement = svgPath.toSVG(path);
svgElement.setAttribute("fill", "#000");
document.getRootElement().appendChild(svgElement);
}
private static void saveSvgDocumentToFile(SVGOMDocument document, File file) throws FileNotFoundException, IOException {
SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
try (Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
svgGenerator.stream(document.getDocumentElement(), out);
}
}
Almost ready. Now we can create SVG file with our GeneralPath inside
GeneralPath path = new GeneralPath();
...
// TODO: set your image width and height ;)
SVGOMDocument document = createSvgDocument(1000,1000);
putPathToSvgDocument(document, path);
// TODO: set your filename :)
saveSvgDocumentToFile(document, new File("c:\\temp\\result.svg"));
Done!
Anyone looking forward to an answer to this would probably be someone like me. Newbie into image processing and looking for libraries that can quench the thirsts of your expedition. I haven't found solution to this problem and I cannot guide you anyone wrongly that what else can be done.
I observed that most of the image processing libraries are written in C++. Fewer libraries are there in Java. Why? Performance. And so for anyone who wants to produce efficient code and all the algorithms input be appreciated should use C++ too.
I want above solution for my Android application. I am going to write code in C++ and connect it via Android NDK.
For all other lost souls, be brave and take this decision. Here is my evidence to prove that.
I'm trying to create a JPanel that has a picture as the background, this I'm able to do but as seen in the GIF there seems to be some kind of painting issue when selecting different entries from the JList. The JList has nothing special about it except that it has an alpha value of 65, meaning it is mostly transparent. I would like to know how to fix the weird visual glitch.
The code for my custom JPanel...
package com.css.aor.graphics;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
/**
* #author Asmicor
*/
public class JImagePanel extends JPanel {
private static final long serialVersionUID = 248015296776870365L;
private Image img;
private boolean autoScale;
/**
* A JPanel that draws an image as the background in the center of the panel
*
* #param img Image that will be drawn as the background
* #param autoScale Should the image be scaled to fit the whole space of the panel
*/
public JImagePanel(Image img, boolean autoScale) {
this.img = img;
this.autoScale = autoScale;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (autoScale) {
int h = img.getHeight(null);
int w = img.getWidth(null);
// Scale Horizontally:
if (w > this.getWidth()) {
img = img.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
h = img.getHeight(null);
}
// Scale Vertically:
if (h > this.getHeight()) {
img = img.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
}
// Center Images
int x = (getWidth() - img.getWidth(null)) / 2;
int y = (getHeight() - img.getHeight(null)) / 2;
g.drawImage(img, x, y, this);
}
}
When I add a repaint() after g.drawImage the problem seems to be solved but as far as I know this is not a good thing to do.
EDIT:
I noticed that when I add a listener to the JList for when the selected value is changed and then call repaint on the whole frame this issue also seems to be solved, so I'm thinking that something is going wrong with the order of the repainting of the components.
Example runnable code...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.AbstractListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
public class Test {
private class JImagePanel extends JPanel {
private static final long serialVersionUID = 248015296776870365L;
private Image img;
private boolean autoScale = false;
/**
* A JPanel that draws an image as the background in the center of the panel
*
* #param img Image that will be drawn as the background
* #param autoScale Should the image be scaled to fit the whole space of the panel
*/
public JImagePanel(Image img, boolean autoScale) {
this.img = img;
this.autoScale = autoScale;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
if (autoScale) {
int h = img.getHeight(null);
int w = img.getWidth(null);
// Scale Horizontally:
if (w > this.getWidth()) {
img = img.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
h = img.getHeight(null);
}
// Scale Vertically:
if (h > this.getHeight()) {
img = img.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
}
// Center Images
int x = (getWidth() - img.getWidth(null)) / 2;
int y = (getHeight() - img.getHeight(null)) / 2;
g.drawImage(img, x, y, this);
}
}
}
private JFrame frame;
private JImagePanel panel;
private JList list;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Test() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JImagePanel(Toolkit.getDefaultToolkit().getImage("C:\\Users\\Asmicor\\Desktop\\lh8vuSc.png"), true); // <-------- Just change this to a viable path
frame.getContentPane().add(panel, BorderLayout.CENTER);
list = new JList();
list.setModel(new AbstractListModel() {
String[] values = new String[] {"ghgfhgfhgfhgfhgfh", "gfhgfhgfhgfhgfhgfh", "gfhgfhgfhgfhgfhgfh", "gfhgfhgfhgfhdshs", "hgdfgdsfgsgdsfgdsfg", "dfhgfhdgfhdfhgfdhdgh"};
public int getSize() {
return values.length;
}
public Object getElementAt(int index) {
return values[index];
}
});
list.setBackground(new Color(0, 125, 50, 65));
GroupLayout gl_panel = new GroupLayout(panel);
gl_panel.setHorizontalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(Alignment.TRAILING, gl_panel.createSequentialGroup()
.addContainerGap(41, Short.MAX_VALUE)
.addComponent(list, GroupLayout.PREFERRED_SIZE, 359, GroupLayout.PREFERRED_SIZE)
.addGap(34))
);
gl_panel.setVerticalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panel.createSequentialGroup()
.addGap(19)
.addComponent(list, GroupLayout.PREFERRED_SIZE, 208, GroupLayout.PREFERRED_SIZE)
.addContainerGap(34, Short.MAX_VALUE))
);
panel.setLayout(gl_panel);
}
}
EDIT2: From what I can gather it happens to any component that has a transparent background that is drawn over the image. I tested it on a JLabel as well as a JTable, both have similar visual glitches. The only real fix is to add repaint() to my paintComponent of JImagePanel, but my CPU usage is really high then.
I have tried to save the JFrame as an image using the following approach.
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
this.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Test.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception unable to write image");
}
I am trying to save a screenshot as follows:
I would like to have even the title in my screenshot
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DividedSquare {
public static void main(String[] args) {
new DividedSquare();
}
public DividedSquare() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private TriangleShape baseTriangle;
private Color[] colors;
public TestPane() {
colors = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA};
}
#Override
public void invalidate() {
super.invalidate();
baseTriangle = new TriangleShape(
new Point(0, 0),
new Point(getWidth(), 0),
new Point(getWidth() / 2, getHeight() / 2));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text[] = new String[]{
"123.123",
"456.789",
"012.315",
"678.921"
};
FontMetrics fm = g2d.getFontMetrics();
double angel = 0;
for (int index = 0; index < 4; index++) {
g2d.setColor(colors[index]);
Path2D rotated = rotate(baseTriangle, angel);
g2d.fill(rotated);
Rectangle bounds = rotated.getBounds();
int x = bounds.x + ((bounds.width - fm.stringWidth(text[0])) / 2);
int y = bounds.y + (((bounds.height - fm.getHeight()) / 2) + fm.getAscent());
g2d.setColor(Color.WHITE);
g2d.drawString(text[index], x, y);
angel += 90;
}
g2d.setColor(Color.BLACK);
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.drawLine(getWidth(), 0, 0, getHeight());
g2d.dispose();
try
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
frame.paint(image.getGraphics());
ImageIO.write(image,"png", new File("Practice.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
public Path2D rotate(TriangleShape shape, double angel) {
Rectangle bounds = shape.getBounds();
int x = bounds.width / 2;
int y = bounds.width / 2;
return new Path2D.Float(shape, AffineTransform.getRotateInstance(
Math.toRadians(angel),
x,
y));
}
}
public class TriangleShape extends Path2D.Double {
public TriangleShape(Point2D... points) {
moveTo(points[0].getX(), points[0].getY());
lineTo(points[1].getX(), points[1].getY());
lineTo(points[2].getX(), points[2].getY());
closePath();
}
}
}
But I the image does not get created. I am unable to understand why.
I looked at this but am unable to understand how to incorporate it in my case.
Edit
Based on comments, I tried using robot class but am unable to know where to call this function from. If I call this function from the paint() method, I am unable to get the colors and text.
void screenshot()
{
try
{
Robot robot = new Robot();
// Capture the screen shot of the area of the screen defined by the rectangle
Point p = frame.getLocationOnScreen();
System.out.print("point" + p);
BufferedImage bi=robot.createScreenCapture(new Rectangle((int)p.getX(),(int)p.getY(),frame.getWidth(),frame.getHeight()));
ImageIO.write(bi, "png", new File("imageTest.png"));
}
catch(Exception exception)
{
//code
System.out.print("Exception to write image");
}
}
There are at least two ways you might achieve this...
You Could...
Use Robot to capture a screen shot. For example
The problem with this is it takes a little effort to target the component you want to capture. It also only captures a rectangular area, so if the component is transparent, Robot won't respect this...
You Could...
Use printAll to render the component to your own Graphics context, typically from a BufferedImage
printAll allows you to print a component, because the intention is not to print this to the screen, printAll disables double buffering, making it more efficient to use when you don't want to render the component to the screen, such printing it to a printer...
Forexample
You can use Robot to capture screenshot. But it not gives Jframe Screenshot. We need to give correct coordinates and refer the frame. gFrame is my frame name and below code works for only Jframe area screenshot.
try {
Robot cap=new Robot();
Rectangle rec=new Rectangle(gFrame.getX(),gFrame.getY(),gFrame.getWidth(),gFrame.getHeight());
BufferedImage screenshot=cap.createScreenCapture(rec);
ImageIO.write(screenshot, "JPG",
new File("C:\\Users\\ruwan\\Downloads\\screenshot.jpg");
} catch (Exception e) {
e.printStackTrace();
}
Is there any way to split an image to region (right now it's JLabel but I can change it if necessary)?
I use swing in my program and I have an image (square for this example) with some triangles, stars and trapezoids inside it (it can be JPG, PNG, etc).
The idea is that the user will click inside one of those shapes and then I will put another small icon on top of the area the user clicked. The user can click on multiple areas but at the end of the day, I need to know which shapes were clicked.
Seems possible anyone?
Have a look at what I have made:
This is the image I used for testing:
After image has been split:
And here is the source:
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Test {
private JFrame frame;
private JLabel[] labels;
private static String imagePath = "c:/test.jpg";
private final int rows = 3; //You should decide the values for rows and cols variables
private final int cols = 3;
private final int chunks = rows * cols;
private final int SPACING = 10;//spacing between split images
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test().createAndShowUI();
}
});
}
private void createAndShowUI() {
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void initComponents() {
BufferedImage[] imgs = getImages();
//set contentpane layout for grid
frame.getContentPane().setLayout(new GridLayout(rows, cols, SPACING, SPACING));
labels = new JLabel[imgs.length];
//create JLabels with split images and add to frame contentPane
for (int i = 0; i < imgs.length; i++) {
labels[i] = new JLabel(new ImageIcon(Toolkit.getDefaultToolkit().createImage(imgs[i].getSource())));
frame.getContentPane().add(labels[i]);
}
}
private BufferedImage[] getImages() {
File file = new File(imagePath); // I have bear.jpg in my working directory
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
BufferedImage image = null;
try {
image = ImageIO.read(fis); //reading the image file
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
int chunkWidth = image.getWidth() / cols; // determines the chunk width and height
int chunkHeight = image.getHeight() / rows;
int count = 0;
BufferedImage imgs[] = new BufferedImage[chunks]; //Image array to hold image chunks
for (int x = 0; x < rows; x++) {
for (int y = 0; y < cols; y++) {
//Initialize the image array with image chunks
imgs[count] = new BufferedImage(chunkWidth, chunkHeight, image.getType());
// draws the image chunk
Graphics2D gr = imgs[count++].createGraphics();
gr.drawImage(image, 0, 0, chunkWidth, chunkHeight, chunkWidth * y, chunkHeight * x, chunkWidth * y + chunkWidth, chunkHeight * x + chunkHeight, null);
gr.dispose();
}
}
return imgs;
}
}
The only flaw is I haven't checked if the image is larger then the screen which could cause problems, that would be resolved by a simple image resize using getScaledInstance(int x,int y, int width, in height) on the image and the separating it into chunks.
Update
Sorry I missed the part if the question in Shapes, have a look at draw(Shape s) method of Graphics2D/Graphics.
I read this:
Any Shape object can be used as a clipping path that restricts the
portion of the drawing area that will be rendered. The clipping path
is part of the Graphics2D context; to set the clip attribute, you call
Graphics2D.setClip and pass in the Shape that defines the clipping
path you want to use.
See here for clipping an u]image to a shape: Clipping the Drawing Region
References:
How to Split an Image into Chunks - Java ImageIO
You can use the getSubImage() method of BufferedImage, illustrated here and here. The example also uses JLabel, but you can add the Icon to a JButton that can be clicked. There are several ways for a button to remember details about it's icon:
Subclass JButton and add a suitable field.
Add a client property to the parent JComponent.
Use the name property of the parent Component.