I wanted to print what is on the canvas and came across this suggested code:
//https://www.cis.upenn.edu/~bcpierce/courses/629/jdkdocs/guide/awt/designspec/printing.html
PrintJob pjob = getToolkit().getPrintJob(new Frame(), "Print TimeGraph", null);
if(pjob !=null) {
Graphics pg = pjob.getGraphics();
if (pg != null) {
canvas.printAll(pg);
pg.dispose(); // flush page
}
pjob.end();
}
Then in the canvas paint method:
#Override
public void paint(Graphics g) {
if(g instanceof PrintGraphics){
if(graphTitle != null){
g.drawString ("Hello Printer",left+10,top+50);
}
}
}
It printed but some of the margins were cut off. I read that awt.printable enabled better margin control so I changed the code to:
PrinterJob pj = PrinterJob.getPrinterJob();
PageFormat pf = pj.defaultPage();
Paper paper = new Paper();
double margin = 4.5;
paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
pf.setPaper(paper);
pj.setPrintable(new MyPrintable(), pf);
if (pj.printDialog()) {
try {
pj.print();
} catch (PrinterException pp) {
System.out.println(pp);
}
}
and
class MyPrintable implements Printable {
public int print(Graphics g, PageFormat pf, int pageIndex) {
if (pageIndex != 0)
return NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D) g;
g2.translate(pf.getImageableX(), pf.getImageableY());
canvas.printAll(g);
return PAGE_EXISTS;
}
}
And that solved the margin issue. The problem is that I no longer get an instanceof PrintGraphics in the paint event. Its always a Graphics object an there is no way to print additional information when paint is invoked from printing. I tried casting the Graphics object to a PrintGraphics object in the canvas.printAll method to no avail. How can I regain the ability to differentiate what called the paint method either by checking the object type or by some other means?
Perhaps hackish but an indirection with extra parameter, on the line of the code below, may solve your problem for the moment.
class MyCanvas {
protected void doPaint(Graphics g, boolean forPrinter) {
if(forPrinter){
if(graphTitle != null){
g.drawString ("Hello Printer",left+10,top+50);
}
}
}
#Override
public void paint(Graphics g) {
this.doPaint(g, false);
}
}
class MyPrintable implements Printable {
public int print(Graphics g, PageFormat pf, int pageIndex) {
if (pageIndex != 0)
return NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D) g;
g2.translate(pf.getImageableX(), pf.getImageableY());
// If on many pages, this will need to be handled better.
// But as are ignoring the pageIndex, I assume
// you are on a single page and pleased to print everything on it
canvas.doPaint(g, true);
return PAGE_EXISTS;
}
}
PS: unless you really want to have a "composite printable" it is much better to make you MyCanvas implement the Printable interface itself.This implies: move the public int print(Graphics g, PageFormat pf, int pageIndex) inside the MyCanvas class itself - cannot hurt and it helps if you want to print something you compute using the MyCanvas non-public members.
Related
I'm nervous about asking this because I'm scared I'll get told off. I am trying to print a JPanel that is about 4 pages long. It could be more, the data is from a JDBC MySql query, that could end up being many more that 4. The JPanel I am trying to print is full of other JPanels (with competitors race details on them) that I have added via a ListArray..
Anyway, I have scoured all day through stackoverflow and have found may examples of code that I have tried to implement. The printable class only prints the first page, so I have tried to implement the pageable class, but I just can't seem to get it right. I have tried to implement the Book class but don't know how to add my JPanel to the book. I have looked here, here and many more (I'm only allowed to post 2 links).
Here is my current code (that I got off one of the answers that #madprogrammer gave) -
int printButton = JOptionPane.showOptionDialog(null, scrollPane, "Race Winners", JOptionPane.YES_NO_OPTION,
JOptionPane.PLAIN_MESSAGE, // no Icon
null, //do not use a custom Icon
options, //the titles of buttons
options[0]); //default button title
if (printButton == 0) {
try {
printComponent(pane, true);
//printComponentToFile(pane, false);
} catch (PrinterException exp) {
exp.printStackTrace();
}
public static void printComponent(JComponent comp, boolean fill) throws PrinterException {
PrinterJob pjob = PrinterJob.getPrinterJob();
//pjob.setPageable(comp);
PageFormat pf = pjob.defaultPage();
pf.setOrientation(PageFormat.PORTRAIT);
PageFormat postformat = pjob.pageDialog(pf);
if (pf != postformat) {
//Set print component
//pjob.setPageable(comp);
pjob.setPrintable(new ComponentPrinter(comp, fill), postformat);
if (pjob.printDialog()) {
pjob.print();
}
}
}
public static void printComponentToFile(Component comp, boolean fill) throws PrinterException {
Paper paper = new Paper();
paper.setSize(8.3 * 72, 11.7 * 72);
paper.setImageableArea(18, 18, 559, 783);
PageFormat pf = new PageFormat();
pf.setPaper(paper);
pf.setOrientation(PageFormat.PORTRAIT);
BufferedImage img = new BufferedImage(
(int) Math.round(pf.getWidth()), (int) Math.round(pf.getHeight()),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
ComponentPrinter cp = new ComponentPrinter(comp, fill);
try {
cp.print(g2d, pf, 0);
} finally {
g2d.dispose();
}
try {
ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ComponentPrinter implements Printable, Pageable {
private Component comp;
private boolean fill;
int numPages;
PageFormat format;
public ComponentPrinter(Component comp, boolean fill) {
this.comp = comp;
this.fill = fill;
}
#Override
public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {
numPages = (int) Math.ceil(comp.getHeight() / format.getImageableY());
System.out.print(numPages);
if (page_index > 0) {
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) g;
g2.translate(format.getImageableX(), format.getImageableY());
//g2.translate(format.getImageableX(), format.getImageableY()- page_index*comp.getPreferredSize().height);
double width = (int) Math.floor(format.getImageableWidth());
double height = (int) Math.floor(format.getImageableHeight());
if (!fill) {
width = Math.min(width, comp.getPreferredSize().width);
height = Math.min(height, comp.getPreferredSize().height);
}
comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
if (comp.getParent() == null) {
comp.addNotify();
}
comp.validate();
comp.doLayout();
comp.printAll(g2);
if (comp.getParent() != null) {
comp.removeNotify();
}
return Printable.PAGE_EXISTS;
}
#Override
public int getNumberOfPages() {
// TODO Auto-generated method stub
return numPages;
}
#Override
public PageFormat getPageFormat(int arg0) throws IndexOutOfBoundsException {
return format;
}
#Override
public Printable getPrintable(int arg0) throws IndexOutOfBoundsException {
// TODO Auto-generated method stub
return this;
}
}
This all works, but only prints the first page. I would REALLY appreciate a nudge in the right direction with this as I'm stumped. TIA :-)
This is how you print a Component (JPanel) on multiple pages:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.*;
import javax.swing.RepaintManager;
public class PrintMultiPageUtil implements Printable, Pageable {
private Component componentToBePrinted;
private PageFormat format;
private int numPages;
public PrintMultiPageUtil(Component componentToBePrinted) {
this.componentToBePrinted = componentToBePrinted;
// get total space from component
Dimension totalSpace = this.componentToBePrinted.getPreferredSize();
// calculate for DIN A4
format = PrinterJob.getPrinterJob().defaultPage();
numPages = (int) Math.ceil(totalSpace .height/format.getImageableHeight());
}
public void print() {
PrinterJob printJob = PrinterJob.getPrinterJob();
// show page-dialog with default DIN A4
format = printJob.pageDialog(printJob.defaultPage());
printJob.setPrintable(this);
printJob.setPageable(this);
if (printJob.printDialog())
try {
printJob.print();
} catch(PrinterException pe) {
System.out.println("Error printing: " + pe);
}
}
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
if ((pageIndex < 0) | (pageIndex >= numPages)) {
return(NO_SUCH_PAGE);
} else {
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY() - pageIndex * pageFormat.getImageableHeight());
disableDoubleBuffering(componentToBePrinted);
componentToBePrinted.paint(g2d);
enableDoubleBuffering(componentToBePrinted);
return(PAGE_EXISTS);
}
}
public static void disableDoubleBuffering(Component c) {
RepaintManager currentManager = RepaintManager.currentManager(c);
currentManager.setDoubleBufferingEnabled(false);
}
public static void enableDoubleBuffering(Component c) {
RepaintManager currentManager = RepaintManager.currentManager(c);
currentManager.setDoubleBufferingEnabled(true);
}
#Override
public int getNumberOfPages() {
// TODO Auto-generated method stub
return numPages;
}
#Override
public PageFormat getPageFormat(int arg0) throws IndexOutOfBoundsException {
return format;
}
#Override
public Printable getPrintable(int arg0) throws IndexOutOfBoundsException {
// TODO Auto-generated method stub
return this;
}
}
numPages
I changed the expression for numPages to:
(int) Math.ceil(page.height/format.getImageableHeight())
This divides the total height (height of the jpanel) through the height of one page, thus calculating the number of all pages.
g2d.translate
I did the following change: In this line:
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY() - pageIndex * pageFormat.getImageableHeight());
Changed componentToBePrinted.getPreferredSize().height to pageFormat.getImageableHeight(). A positive value for the first or the second parameter of g2d.translate moves the graphic to the right or down respectively.
.getImageableX() and .getImageableY() help position the graphic so that it doesn't overlap with the padding.
For pageIndex greater than 0, - pageIndex * pageFormat.getImageableHeight() moves the image pageIndex-times the page-height to the top. So the area, that the pageIndex refers to is printed.
original broken source:: https://community.oracle.com
Here is my original answer.
I am using the following codes to print and save the data in pdf format but it doesn't worked. So, what is the code to print the information of jframe in netbeans in pdf format.
PrinterJob job = PrinterJob.getPrinterJob();
job.setJobName("jPanel2");
job.setPrintable (new Printable()
{
public int print(Graphics pg, PageFormat pf, int pageNum)
{
if (pageNum > 0)
{
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) pg;
g2.translate(pf.getImageableX(), pf.getImageableY());
jPanel2.paint(g2);
return Printable.PAGE_EXISTS;
}
});
boolean ok = job.printDialog();
if (ok)
{
try
{
job.print();
}
catch (PrinterException ex)
{
}
}
I have an image, with a complete transparent background. However when I draw this image, ingame, it has a kind of shade to it, and I have no clue why. I would like to get that out of there. Does anyone have an idea? I don't have the reputation to post images of it apparently... So I'll try to give some more information.
I have the Color.DARK_GRAY as background, and when I draw the image, you see a lighter gray square around it.
Then when I draw a couple of these images ontop of eachother, that square gets lighter and lighter.
If I draw the image ontop of another image however, this effect does not occur.
Here I load the image
public BlackChip() {
this.value = 500;
this.url = "res/images/poker/blackchip.png";
this.file = new File(url);
BufferedImage bi;
try {
bi = ImageIO.read(file);
this.image = bi;
} catch (IOException e) {
e.printStackTrace();
}
}
Here I draw the image
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Here I call that method
public void render() {
screen.renderBackground(Color.DARK_GRAY);
pokertable.render(Game.width / 2 - pokertable.getImage().getWidth(null) / 2, 50);
screen.renderChip(cs.getWhiteChip(), 380, 310);
screen.renderChip(cs.getRedChip(), 430, 310);
screen.renderChip(cs.getGreenChip(), 480, 310);
screen.renderChip(cs.getBlueChip(), 530, 310);
screen.renderChip(cs.getBlackChip(), 580, 310); //this one is it
}
link to the images:
https://drive.google.com/file/d/0Bz-4pfUssUeHRWkxaUhodWNILWc/edit?usp=sharing
Well... this doesn't work either because i need 10 reputation to post more then 1 link
you can see the effect on this link, it's the image with full transparent background, drawn multiple times.
I can't tell if this is the exact cause of the problem, because you haven't provided a MCVE but this method
public void renderChip(Chip chip, int x, int y) {
g.drawImage(chip.getImage(), x, y, null);
}
Just looks wrong. All custom painting should be done within the context of the provided Graphics object in the overridden paintComponent method. If you have not overriden paintComponent in a JPanel or a JComponent then you are likely not painting correctly. You may be doing something like
public class SomePanel extends JPanel {
private Graphics g;
public SomePanel() {
g = getGraphics();
}
}
Which is completely wrong. You should instead be doing something like
public class SomePanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// do painting here
}
}
You Classes can then have it's own render method that takes a Graphics object as an argument. Then can be called in the paintComponent method. Maybe something like
public class Chip {
private JComponent imageObserver;
private BufferedImage chipImage;
int x, y;
public Chip(BufferedImage chipImage, int x, int y, JComponent imageObserver){
this.chipImage;
this.x = x;
this.y = y;
this.imageObserver = imageObserver;
}
public void renderChip(Graphics g) {
g.getImage(chipImage, x, y, imageObserver);
}
}
And your panel
public class SomePanel extends JPanel {
private List<Chip> chips;
public SomePanel() {
chips = new ArrayList<Chip>();
// add new Chips
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Chip chip: chips) {
chip.renderChip(g);
}
}
}
As part of a program I am writing, I wish to print an image to SVG format. I need it to be in SVG format, so that I can modify it using Adobe Illustrator later on. As it stands, although I can draw a rectangle directly in the print method and export that successfully to SVG format.
When I draw the same rectangle in my getTagCloud method, the result (when printed to SVG) is a rectangle made up of a huge number of tiny rectangles. I am at a loss as to why this might be so, though hopefully the answer will be blindingly obvious to someone reading this!
Ultimately, I need to print out more than just a rectangle but the exported "Group" in Illustrator is so large (containing as it does all these tiny rectangles of varying sizes) that I am unable to find the other objects I have drawn (as everything, no matter what colour I originally used, is rendered in black). Any help would be greatly appreciated.
Below is the relevant code. I have not included the import statements as I don't have any problems compiling the code.
public class TagCloud {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Tag Cloud Generator");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel myPanel = new MyPanel();
Toolkit tk = f.getToolkit();
Dimension wndSize = tk.getScreenSize();
f.setBounds(0, 0,
wndSize.width, wndSize.height);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
f.add("Center",myPanel);
f.pack();
f.setVisible(true);
myPanel.printTagCloud();
}
}
class MyPanel extends JPanel implements Printable{
private int squareX = 50;
private int squareY = 50;
private int squareW = 20;
private int squareH = 20;
private int x_offset = 30;
private int y_offset = 30;
private BufferedImage img = null;
private int defaultFontSize = 16;
public int print(Graphics g, PageFormat pf, int page) throws
PrinterException {
if (page > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
if (img == null){
getTagCloudImage();
}
g.setColor(Color.red);
g.fillRect(0, 0, 250, 400);
//g.drawImage(img, 0, 0, null);
g.dispose();
return PAGE_EXISTS;
}
public void printTagCloud(){
PrinterJob job = PrinterJob.getPrinterJob();
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PageFormat pf = job.pageDialog(aset);
job.setPrintable(this);
boolean ok = job.printDialog(aset);
if (ok) {
try {
job.print(aset);
} catch (PrinterException ex) {
}
}
}
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
}
private void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(1000,800);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img == null){
getTagCloudImage();
}
else{
g.drawImage(img, x_offset, y_offset, null);
}
}
public void getTagCloudImage(){
img = new BufferedImage(250, 250, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
Graphics2D g2 = (Graphics2D)g;
Rectangle r = new Rectangle (0,0,250,250);
g2.draw(r);
g2.setColor(Color.black);
g2.fill(r);
g2.dispose();
}
I can't help much without knowledge about Java BufferedImage,Graphics, PrinterJob and other related classes implementation. (You may start a bounty for this question to possibly draw attention of people having more intristic knowledge about java awt graphic stuff).
As you obviously must have noticed using BufferedImage (or not using it) is what makes a difference in SVG output. In the version that works you draw the rectangle directly on Graphic context provided to you as print() method argument and I believe that's how it was designed to be used by authors of Printable interface and printing framework.
In the second approach (that doesn't work correct) you first draw rectangle onto new BufferedImage object and then draw this image on the provided Graphic context. So you do something much less straightforward than just drawing directly on the context. There is well known truth or intuition among developers that the less straightforward way do you use some API, the bigger is a chance that you do something unexpected by its authors :(.
My hypotesis is following: BufferedImage is (as you can deduce from its Javadocs)just a raster image, ie. grid of pixels. That's why svg file is populated with lots of small rectangles (trying to mimic pixels). The Graphics object provided by draw() method may be more abstract and operate on shapes rather than pixels, which is much more appropriate to be written to vector graphics formats like SVG. But that's just hypotesis.
The question is, do you really need to use BufferedImage? If I understand correctly, you want user to be able to edit rectangle on screen and when ready export it to SVG. Can't you just remember for example upper left corner and dimensions of rectangle edited by user and then use this data to recreate this rectangle directly on Graphics object provided by print(), like:
public int print(Graphics g, PageFormat pf, int page)
throws PrinterException {
...
g.fillRect(userRect.x,userRect.y,userRect.width,userRect.height);
...
}
?
(userRect is object of your own custom class which just stores data about image edited by user)
private void printCard() {
PrinterJob printjob = PrinterJob.getPrinterJob();
printjob.setJobName("Label");
Printable printable = new Printable() {
public int print(Graphics pg, PageFormat pf, int pageNum) {
if (pageNum > 0) {
return Printable.NO_SUCH_PAGE;
}
Dimension size = jLayeredPane2.getSize();
BufferedImage bufferedImage = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
jLayeredPane2.print(bufferedImage.getGraphics());
Graphics2D g2 = (Graphics2D) pg;
g2.translate(pf.getImageableX(), pf.getImageableY());
g2.drawImage(bufferedImage, 0, 0, (int) pf.getWidth(), (int) pf.getHeight(), null);
return Printable.PAGE_EXISTS;
}
};
Paper paper = new Paper();
paper.setImageableArea(0, 0, 153, 243);
paper.setSize(243, 154);
PageFormat format = new PageFormat();
format.setPaper(paper);
format.setOrientation(PageFormat.LANDSCAPE);
printjob.setPrintable(printable, format);
if (printjob.printDialog() == false)
return;
try {
printjob.print();
} catch (PrinterException ex) {
System.out.println("NO PAGE FOUND." + ex);
}
}
From what I see in your code, you call if (printjob.printDialog() == false). This will always try to show the native printer properties dialog. The boolean return value is based on whether the user clicks OK or cancels out of the dialog. If you want to suppress the dialog, remove that if block, as the printing work that you want to perform is done via the printjob.print() call.