java setting resolution and print size for an Image - java

I wrote a program that generates a BufferedImage to be displayed on the screen and then printed. Part of the image includes grid lines that are 1 pixel wide. That is, the line is 1 pixel, with about 10 pixels between lines. Because of screen resolution, the image is displayed much bigger than that, with several pixels for each line. I'd like to draw it smaller, but when I scale the image (either by using Image.getScaledInstance or Graphics2D.scale), I lose significant amounts of detail.
I'd like to print the image as well, and am dealing with the same problem. In that case, I am using this code to set the resolution:
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
PrinterResolution pr = new PrinterResolution(250, 250, ResolutionSyntax.DPI);
set.add(pr);
job.print(set);
which works to make the image smaller without losing detail. But the problem is that the image is cut off at the same boundary as if I hadn't set the resolution. I'm also confused because I expected a larger number of DPI to make a smaller image, but it's working the other way.
I'm using java 1.6 on Windows 7 with eclipse.

Regarding the image being cut-off on the page boundary, have you checked the clip region of the graphics? I mean try :
System.out.println(graphics.getClipBounds());
and make sure it is correctly set.

I had the same problem. Here is my solution.
First change the resolution of the print job...
PrinterJob job = PrinterJob.getPrinterJob();
// Create the paper size of our preference
double cmPx300 = 300.0 / 2.54;
Paper paper = new Paper();
paper.setSize(21.3 * cmPx300, 29.7 * cmPx300);
paper.setImageableArea(0, 0, 21.3 * cmPx300, 29.7 * cmPx300);
PageFormat format = new PageFormat();
format.setPaper(paper);
// Assign a new print renderer and the paper size of our choice !
job.setPrintable(new PrintReport(), format);
if (job.printDialog()) {
try {
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
PrinterResolution pr = new PrinterResolution((int) (dpi), (int) (dpi), ResolutionSyntax.DPI);
set.add(pr);
job.setJobName("Jobname");
job.print(set);
} catch (PrinterException e) {
}
}
Now you can draw everything you like into the new high resolution paper like this !
public class PrintReport implements Printable {
#Override
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
// Convert pixels to cm to lay yor page easy on the paper...
double cmPx = dpi / 2.54;
Graphics2D g2 = (Graphics2D) g;
int totalPages = 2; // calculate the total pages you have...
if (page < totalPages) {
// Draw Page Header
try {
BufferedImage image = ImageIO.read(ClassLoader.getSystemResource(imgFolder + "largeImage.png"));
g2.drawImage(image.getScaledInstance((int) (4.8 * cmPx), -1, BufferedImage.SCALE_SMOOTH), (int) (cmPx),
(int) (cmPx), null);
} catch (IOException e) {
}
// Draw your page as you like...
// End of Page
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}

It sounds like your problem is that you are making the grid lines part of the BufferedImage and it doesn't look good when scaled. Why not use drawLine() to produce the grid after your image has been drawn?

Code for Convert image with dimensions using Java and print the converted image.
Class: ConvertImageWithDimensionsAndPrint.java
package com.test.convert;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class ConvertImageWithDimensionsAndPrint {
private static final int IMAGE_WIDTH = 800;
private static final int IMAGE_HEIGHT = 1000;
public static void main(String[] args) {
try {
String sourceDir = "C:/Images/04-Request-Headers_1.png";
File sourceFile = new File(sourceDir);
String destinationDir = "C:/Images/ConvertedImages/";//Converted images save here
File destinationFile = new File(destinationDir);
if (!destinationFile.exists()) {
destinationFile.mkdir();
}
if (sourceFile.exists()) {
String fileName = sourceFile.getName().replace(".png", "");
BufferedImage bufferedImage = ImageIO.read(sourceFile);
int type = bufferedImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : bufferedImage.getType();
BufferedImage resizedImage = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, type);
Graphics2D graphics2d = resizedImage.createGraphics();
graphics2d.drawImage(bufferedImage, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);//resize goes here
graphics2d.dispose();
ImageIO.write(resizedImage, "png", new File( destinationDir + fileName +".png" ));
int oldImageWidth = bufferedImage.getWidth();
int oldImageHeight = bufferedImage.getHeight();
System.out.println(sourceFile.getName() +" OldFile with Dimensions: "+ oldImageWidth +"x"+ oldImageHeight);
System.out.println(sourceFile.getName() +" ConvertedFile converted with Dimensions: "+ IMAGE_WIDTH +"x"+ IMAGE_HEIGHT);
//Print the image file
PrintActionListener printActionListener = new PrintActionListener(resizedImage);
printActionListener.run();
} else {
System.err.println(destinationFile.getName() +" File not exists");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Reference of PrintActionListener.java
package com.test.convert;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
public class PrintActionListener implements Runnable {
private BufferedImage image;
public PrintActionListener(BufferedImage image) {
this.image = image;
}
#Override
public void run() {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(new ImagePrintable(printJob, image));
if (printJob.printDialog()) {
try {
printJob.print();
} catch (PrinterException prt) {
prt.printStackTrace();
}
}
}
public class ImagePrintable implements Printable {
private double x, y, width;
private int orientation;
private BufferedImage image;
public ImagePrintable(PrinterJob printJob, BufferedImage image) {
PageFormat pageFormat = printJob.defaultPage();
this.x = pageFormat.getImageableX();
this.y = pageFormat.getImageableY();
this.width = pageFormat.getImageableWidth();
this.orientation = pageFormat.getOrientation();
this.image = image;
}
#Override
public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex == 0) {
int pWidth = 0;
int pHeight = 0;
if (orientation == PageFormat.PORTRAIT) {
pWidth = (int) Math.min(width, (double) image.getWidth());
pHeight = pWidth * image.getHeight() / image.getWidth();
} else {
pHeight = (int) Math.min(width, (double) image.getHeight());
pWidth = pHeight * image.getWidth() / image.getHeight();
}
g.drawImage(image, (int) x, (int) y, pWidth, pHeight, null);
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}
}
Output:
04-Request-Headers_1.png OldFile with Dimensions: 1224x1584
04-Request-Headers_1.png ConvertedFile converted with Dimensions: 800x1000
After conversion of a image a Print window will be open for printing the converted image. The window displays like below, Select the printer from Name dropdown and Click OK button.

You can use either of the following to improve the quality of the scaling. I believe BiCubic gives better results but is slower than BILINEAR.
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
I would also not use Image.getScaledInstance() as it is very slow. I'm not sure about the printing as I'm struggling with similar issues.

Related

Java code not able to print long receipt in thermal printer

My java thermal printer code not able to print long receipt(more than A4 sheet size). Its work fine normally, but in case where there is too much items in cart then it generate half print. My code is under mentioned-
public PrintReceipt(Map<String,String> hm){
/*
product details code..
*/
try{
input = new FileInputStream("C:/printer.properties");
prop.load(input);
printerName=prop.getProperty("receiptPrinter");
System.out.println("Printer Name "+printerName);
}catch(Exception exception){
System.out.println("Properties file not found");
}
PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null,null);
for (int i = 0; i < pservices.length; i++) {
if (pservices[i].getName().equalsIgnoreCase(printerName)) {
job = PrinterJob.getPrinterJob();
PageFormat pf = job.defaultPage();
double margin = 1.0D;
Paper paper = new Paper();
paper.setSize(216D, paper.getHeight());
paper.setImageableArea(margin, margin, paper.getWidth() - margin * 1.5D, paper.getHeight() - margin * 1.5D);
pf.setPaper(paper);
job.setCopies(1);
pf.setOrientation(1);
job.setPrintable(this, pf);
try
{
job.print();
}
catch(PrinterException ex)
{
System.out.println("Printing failed");
}
}
}
}
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
if(pageIndex > 0)
return 1;
Graphics2D g2d = (Graphics2D)graphics;
double width = pageFormat.getImageableWidth();
double height = pageFormat.getImageableHeight();
g2d.translate((int) pageFormat.getImageableX(),(int) pageFormat.getImageableY());
Font font = new Font("Monospaced",Font.BOLD,8);
g2d.setFont(font);
try {
/*
* Draw Image*
*/
int x=50 ;
int y=10;
int imagewidth=100;
int imageheight=50;
BufferedImage read = ImageIO.read(new File("C:/hotel.png"));
g2d.drawImage(read,x,y,imagewidth,imageheight,null); //draw image
g2d.drawString("-- * Resturant * --", 20,y+60);
g2d.drawLine(10, y+70, 180, y+70); //draw line
} catch (IOException e) {
e.printStackTrace();
}
try{
/*Draw Header*/
/*
product details code..
*/
/*Footer*/
//end of the receipt
}
catch(Exception r){
r.printStackTrace();
}
return 0;
}
Please let me know how can i generate long receipt print by correcting my code or if you have any better solution to do this.
Right here:
Paper paper = new Paper();
paper.setSize(216D, paper.getHeight());
You are creating a new Paper object and not setting its height.
Here is a link to the documentation of this class.
When creating a Paper object, it is the application's responsibility to ensure that the paper size and the imageable area are compatible
You need to set the height of the paper by calling paper.setSize(width, height) or it will use its default size property.
The dimensions are supplied in 1/72nds of an inch.
So both width and height will need to be provided in this format as doubles
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
PrintService service = findPrintService(printerName, printService);
PDDocument document = PDDocument.load(bytes);
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintService(service);
job.setPageable(new PDFPageable(document));
job.print();
if (document != null) {
document.close();
}

Image size returns -1 in JAR but proper size in IDE. Image loaded via Toolkit....createImage(url)

Intention: Get BufferedImage from resource (be it in IDE or running JAR).
Problem: Getting an Image always works, converting to BufferedImage requires knowledge of size, but size always returns -1, even after waiting with MediaTracker. In IDE, size after MediaTracker is proper, before it is -1. Waiting with while-loop until size >-1 seems to never end in running JAR. (Tried with code language level 6 and 8 using JDK/JRE 8.)
Output of SSCCE in IDE:
IMAGE: sun.awt.image.ToolkitImage#15975490
WIDTH: -1
DURATION: 38 ms
WIDTH: 32
BUFFEREDIMAGE: BufferedImage#6adede5: type = 1 DirectColorModel:
rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster:
width = 32 height = 32 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0
EDIT: MediaTracker's "isErrorAny()" returns false.
Output of SSCCE in running JAR:
IMAGE: sun.awt.image.ToolkitImage#2a84aee7
WIDTH: -1
DURATION: 23 ms
WIDTH: -1
Exception in thread "main"
java.lang.IllegalArgumentException: Width (-1) and height (-1) cannot
be <= 0
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown
Source)
at java.awt.image.BufferedImage.(Unknown Source)
at ImageSizeProblem.createBufferedImageFromImage(ImageSizeProblem.java:82)
at ImageSizeProblem.main(ImageSizeProblem.java:26)
EDIT: MediaTracker's "isErrorAny()" returns true. But I have no way of finding out what the error is - also, the image does load properly, since it can be successfully used in an JToolBar via making an ImageIcon from it. (I already tried abusing ImageIcon's getIconWidth() or getImage() methods - they bring no improvement at all.)
SSCCE:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class ImageSizeProblem {
public static void main(final String[] args) {
final Image img = createImageFromResource("test.png");
System.out.println("IMAGE: " + img);
System.out.println("WIDTH: " + img.getWidth(null));
final long startTime = System.currentTimeMillis();
waitForImage(img);
final long duration = System.currentTimeMillis() - startTime;
System.out.println("\nDURATION: " + duration + " ms");
System.out.println("\nWIDTH: " + img.getWidth(null));
final BufferedImage buffImg = createBufferedImageFromImage(img, false);
System.out.println("\nBUFFEREDIMAGE: " + buffImg);
System.exit(0);
}
private static Image createImageFromResource(final String resourceFileName_dontForgetToAddItsFolderToClasspath) {
final Toolkit kit = Toolkit.getDefaultToolkit();
final URL url = ClassLoader.getSystemResource(resourceFileName_dontForgetToAddItsFolderToClasspath);
if (url != null) {
final Image img = kit.createImage(url);
if (img == null) {
System.err.println("Image resource could not be loaded.");
return null;
}
return img;
} else {
System.err.println("Image resource not found.");
return null;
}
}
private static boolean waitForImage(final Image img) {
final MediaTracker mediaTracker = new MediaTracker(new JPanel());
mediaTracker.addImage(img, 1);
try {
mediaTracker.waitForID(1);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return !mediaTracker.isErrorAny();
}
// improved version of http://stackoverflow.com/a/13605411/3500521
private static BufferedImage createBufferedImageFromImage(final Image img, final boolean withTransparency) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
} else if (img == null) {
return null;
}
final int w = img.getWidth(null);
final int h = img.getWidth(null);
final BufferedImage bufferedImage;
if (withTransparency) {
bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
} else {
bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
}
final Graphics2D g = bufferedImage.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bufferedImage;
}
}
Note that the image used for testing was loaded and used successfully in another application via new ImageIcon(image) in a JToolBar. Getting the size from the ImageIcon also returns -1, also from the image returned by ImageIcon.getImage().
The problem was path depth.
I also tried Avira, because the problem is technically a program accessing its own file, which could well seem suspicious, but while Avira was uninstalling, I tried the executables in a different location with a shorter path, and everything worked like a charm.

Java Printing Font Stretch

I just got the printer to work in java how I need it too, but there's one last problem I need to solve. When it prints, the font's width is rather stretched, and not crisp and clear like it should be.
Here is my code my the actual drawing to the paper:
FontMetrics metrics = graphics.getFontMetrics(font);
int lineHeight = metrics.getHeight();
arrangePage(graphics, pageFormat, lineHeight);
if (page > pageBreaks.length){
return NO_SUCH_PAGE;
}
Graphics2D g = (Graphics2D) graphics;
g.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
g.setFont(font);
int y = 0;
int begin = 0;
if (page == 0){
begin = 0;
}else begin = pageBreaks[page-1];
int end = 0;
if (page == pageBreaks.length){
end = lines.length;
}else end = pageBreaks[page];
for (int line = begin; line < end; line++){
y += lineHeight;
g.drawString(lines[line], 0, y);
}
string = deepCopy;
return PAGE_EXISTS;
How do I get rid of the stretching? It can be noted that this is based off this tutorial:
http://docs.oracle.com/javase/tutorial/2d/printing/set.html
Any advice or help is greatly appreciated.
The default DPI is normal 72 DPI (I believe), which, on printed paper, is pretty terrible. You need to prompt the print API to try and find a printer with a better DPI.
Basically you need to use the print services API.
Try something like...
public class PrintTest01 {
public static void main(String[] args) {
PrinterResolution pr = new PrinterResolution(300, 300, PrinterResolution.DPI);
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(MediaSizeName.ISO_A4);
aset.add(pr);
aset.add(OrientationRequested.PORTRAIT);
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(new Page());
try {
pj.print(aset);
} catch (PrinterException ex) {
ex.printStackTrace();
}
}
public static class Page implements Printable {
#Override
public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex > 0) {
return NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
g.setFont(new Font("Arial", Font.PLAIN, 128));
FontMetrics fm = g.getFontMetrics();
int x = (int)(pageFormat.getWidth() - fm.stringWidth("A")) / 2;
int y = (int)((pageFormat.getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString("A", x, y);
return PAGE_EXISTS;
}
}
}
You might find Working with Print Services and Attributes of some help...
I should warn you, this is going to print to the first print that it can find that meets the PrintRequestAttributeSet. You could also add in the print dialog to see what's it doing, but that's another level of complexity I can live without right now ;)
The above worked! To open a print dialog with it, use this:
PrinterJob job = PrinterJob.getPrinterJob();
TextDocumentPrinter document = new TextDocumentPrinter();
PrinterResolution pr = new PrinterResolution(300, 300, PrinterResolution.DPI);
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(MediaSizeName.ISO_A4);
aset.add(pr);
aset.add(OrientationRequested.PORTRAIT);
job.setPrintable(document);
boolean doPrint = false;
if (showDialog){
doPrint = job.printDialog(aset);
}else doPrint = true;
if (doPrint){
try{
job.print();
}catch(PrinterException e){
e.printStackTrace();
}
}
The aset variable contains all of your new default values, and by plugging it into the printDialog, those are inputted into the printJob and consequently show up on the paper! They can be changed in the dialog, as well.

when writing string to image, I get a long, narrow image - how break lines?

I'm trying to write strings to images, so it's harder to copy the text and run it through a translator.
My code works fine, but I get always a really long image - I rather would like to have a more readable box in where the string is written. My method "StringDiver" does add "\n" but it does not help when writing the string to an image.
Right now I get this output.
Any hint what I could do?
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class writeToImage {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String newString = "Mein Eindruck ist, dass die politische und öffentliche Meinung in Deutschland anfängt, die wirtschaftliche Zerstörung im Inland und in Europa zu erkennen, die auf einen eventuellen Zusammenbruch des Euro folgen würde.";
String sampleText = StringDivider(newString);
//Image file name
String fileName = "Image";
//create a File Object
File newFile = new File("./" + fileName + ".jpg");
//create the font you wish to use
Font font = new Font("Tahoma", Font.PLAIN, 15);
//create the FontRenderContext object which helps us to measure the text
FontRenderContext frc = new FontRenderContext(null, true, true);
//get the height and width of the text
Rectangle2D bounds = font.getStringBounds(sampleText, frc);
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
//create a BufferedImage object
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
//calling createGraphics() to get the Graphics2D
Graphics2D g = image.createGraphics();
//set color and other parameters
g.setColor(Color.WHITE);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString(sampleText, (float) bounds.getX(), (float) -bounds.getY());
//releasing resources
g.dispose();
//creating the file
try {
ImageIO.write(image, "jpg", newFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String StringDivider(String s){
StringBuilder sb = new StringBuilder(s);
int i = 0;
while ((i = sb.indexOf(" ", i + 30)) != -1) {
sb.replace(i, i + 1, "\n");
}
return sb.toString();
}
}
g.drawString(sampleText, (float) bounds.getX(), (float) -bounds.getY());
Split text and write every part to image.
Rectangle2D bounds = font.getStringBounds(sampleText, frc);
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
String[] parts = sampleText.split("\n");
//create a BufferedImage object
BufferedImage image = new BufferedImage(w, h * parts.length, BufferedImage.TYPE_INT_RGB);
int index = 0;
for(String part : parts){
g.drawString(part, 0, h * index++);
}
ex:
first part: x=0 ; y=0
second part: x=0 ; y=5
third part: x=0 ; y=10;
heightText = h
Take a look at LineBreakMeasurer. The first code example in the Javadoc is exactly what you're looking for.

Printing two Jpanels in one document

I have two different Panels but i have need to send them in one document in to two pages. first page print at front and the second will print at the back side can anyone please help me i have send one jpanel but how to send second with it. Here is my code
private void printCard() {
PrinterJob printjob = PrinterJob.getPrinterJob();
printjob.setJobName(" CARD ");
Printable printable = new Printable() {
public int print(Graphics pg, PageFormat pf, int pageNum) {
if (pageNum > 0) {
return Printable.NO_SUCH_PAGE;
}
Dimension imageDimension = jLayeredPane2.getSize();
BufferedImage bufferedImage = new BufferedImage(imageDimension.width, imageDimension.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);
Dimension backimage=jLayeredPane4.getSize();
BufferedImage bufferedImage1 = new BufferedImage(backimage.width, backimage.height, BufferedImage.TYPE_INT_RGB);
jLayeredPane4.print(bufferedImage1.getGraphics());
g2.drawImage(bufferedImage1, 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, 153);
PageFormat format = new PageFormat();
format.setPaper(paper);
format.setOrientation(PageFormat.REVERSE_LANDSCAPE);
printjob.setPrintable(printable,format);
try {
printjob.print();
} catch (PrinterException ex) {
System.out.println("Sorry No Image Found" + ex);
}
Thanks
}
Instead of using a java.awt.print.Printable, use java.awt.print.Pageable instead. This will let you specify two pages, and then print in duplex to get front and back. PrinterJob has a setPageable() function as well as a setPrintable(). To make it even easier, use a Book and just add two Printables, one for each page.

Categories