I looked at java.awt.Graphics documentation, stackoverflow, could not find a solution. I have in input two things, an image file and the multi line text (paragraph). I need to write the multi line text on the image file and then save it as a new image. Wondering if I am missing something really simple here.
I am open to using any good third party libraries as well.
final BufferedImage image = ImageIO.read(new File("c:/anil/Lenna.png"));
Graphics g = image.getGraphics();
g.setFont(g.getFont().deriveFont(30f));
g.drawString("Hello world", 100, 100);
g.dispose();
Above code writes just a single line on the image.
if you want to draw several lines you have to do it explicitly...
so first step is to 'detect' lines
String str = ... //some text with line breaks;
String [] lines = str.spilt("\n"); //breaking the lines into an array
second step is to draw all lines
Graphics g = image.getGraphics();
g.setFont(g.getFont().deriveFont(30f));
int lineHeight = g.getFontMetrics().getHeight();
//here comes the iteration over all lines
for(int lineCount = 0; lineCount < lines.length; lineCount ++){ //lines from above
int xPos = 100;
int yPos = 100 + lineCount * lineHeight;
String line = lines[lineCount];
g.drawString(line, xpos, yPos);
}
g.dispose();
JLabel accepts simple html to format text. Then you can paint it on your image:
JLabel l=new JLabel("<html>line1<br>line2");
l.setSize(l.getPrefferedSize());
g.translate(10,10); // fixed location
l.paint(g);
edit: complete example
public class OP_32110247 extends JPanel {
private final JLabel l = new JLabel();
private final BufferedImage image;
public OP_32110247(String imgfile, String txt) throws IOException {
image = ImageIO.read(new URL(imgfile));
l.setText(txt);
l.setFont(getFont().deriveFont(Font.BOLD,30f));
l.setSize(l.getPreferredSize());
l.setForeground(Color.GREEN);
Dimension d = new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(d);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = getSize();
g.drawImage(image, 0, 0, null);
//place text in center of image
g.translate((d.width-l.getWidth())/2, (d.height-l.getHeight())/2);
l.paint(g);
}
public static void main(String[] args) throws IOException {
String txt = "<html>line1<br>line2";
String image = "http://kysoft.pl/proj/java/j+c.png";
JFrame f = new JFrame();
f.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
f.setContentPane(new OP_32110247(image,txt));
f.pack();
f.setVisible(true);
}
}
The best solution is to extend JLabel and override paintComponent. Create the Label with the image required. After calling super.paintComponent draw your text, each line positioning below another using the font metrics. Something like below:
class ImageWithTextLabel extends JLabel {
List<String> lines = new ArrayList<>();
Point textPosition = new Point(0,0);
private Font textFont;
private ImageWithTextLabel(Icon image) {
super(image);
}
public void addText(String text) {
lines.add(text);
}
public void setTextPosition(Point textPosition) {
this.textPosition = textPosition;
}
#Override protected void paintComponent(Graphics g) {
super.paintComponent(g);
int from = textPosition.y ;
g.setFont(textFont);
for (String line : lines) {
g.drawString(line, textPosition.x, from);
from += g.getFontMetrics().getHeight();
}
}
public void setTextFont(Font font) {
textFont = font;
}
}
see Drawing Multiple Lines of Text(Oracle Java Tutorials) and complete code
use LineBreakMeasurer:
int width = 400;
int height = 500;
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setColor(Color.MAGENTA);
Hashtable<TextAttribute,Object> map = new Hashtable<TextAttribute,Object>();
map.put(TextAttribute.FAMILY, "微软雅黑");
map.put(TextAttribute.SIZE,new Float(18.0));
AttributedString vanGogh = new AttributedString(
"Many people 中国 believe that Vincent van Gogh painted his best works " +
"during the two-year period he spent in Provence. Here is where he " +
"painted The Starry Night--which some consider to be his greatest " +
"work of all. However, as his artistic brilliance reached new " +
"heights in Provence, his physical and mental health plummeted. ",
map);
AttributedCharacterIterator paragraph = vanGogh.getIterator();
int paragraphStart = paragraph.getBeginIndex();
int paragraphEnd = paragraph.getEndIndex();
FontRenderContext frc = g2d.getFontRenderContext();
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
float breakWidth = 250f;
float drawPosY = 20;
float drawPosx = 0f;
lineMeasurer.setPosition(paragraphStart);
while(lineMeasurer.getPosition()< paragraphEnd ){
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
drawPosx = layout.isLeftToRight()?0:breakWidth-layout.getAdvance();
drawPosY += layout.getAscent();
layout.draw(g2d,drawPosx,drawPosY);
drawPosY += layout.getDescent() + layout.getLeading();
}
g2d.dispose();
File file = new File("myimage.png");
ImageIO.write(bufferedImage,"png",file);
file = new File("myimage.jpg");
ImageIO.write(bufferedImage,"jpg",file);
Related
I am attempting to pull an image from a url using URLImage.createToStorage. However I want that picture to appear rounded so I add a Mask to the image. However when I run the label only shows the placeholder image, not the url image. When I comment out the code that adds the rounded mask to the image the image displays. Is there something wrong with my rounded image code. I used Display.getInstance().callSerially().
//Where I display the image.
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image img = getImageFromRes("myprofile.png");
Image scaled = img.scaledWidth(f.getWidth() / 2);
EncodedImage enc = EncodedImage.createFromImage(scaled, false);
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
imageLabel.setIcon(getRoundedImage(URLImage.createToStorage(enc,
"profileImage8", me.getPicture(), URLImage.RESIZE_SCALE_TO_FILL)));
f.revalidate();
}
});
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
public Image getRoundedImage(Image img) {
int w = img.getWidth();
int h = img.getHeight();
Image maskImage = Image.createImage(w, h);
Graphics g = maskImage.getGraphics();
g.setColor(0xffffff);
g.fillArc(0, 0, w, h, 0, 360);
Object mask = maskImage.createMask();
Image ret = img.applyMask(mask);
return ret;
}
The setUpProfile() method is called in the beforeShow of the Form.
EDIT: I edited in the working setUpProfile() method which uses URLImage.createMaskAdapter. and achieves a rounded image.
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image mask = getImageFromRes("rounded-mask.png");
Image placeholder = getImageFromRes("myprofile.png").scaled(mask.getWidth(), mask.getHeight());
EncodedImage enc = EncodedImage.createFromImage(placeholder.applyMask(mask.createMask()),
false);
System.out.println("SetUpProfile picture " + me.getPicture());
imageLabel.setIcon(URLImage.createToStorage(enc, "profileImage8",
me.getPicture(), URLImage.createMaskAdapter(mask)));
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
You can achieve this by creating a custom ImageAdapter that generates a round-mask automatically for you while downloading the image.
public static final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp.getWidth() > placeholderImage.getWidth()) {
int diff = tmp.getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp.getHeight() > placeholderImage.getHeight()) {
int diff = tmp.getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
}
Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp = tmp.applyMask(mask);
return EncodedImage.createFromImage(tmp, false);
}
#Override
public boolean isAsyncAdapter() {
return true;
}
};
Then apply it this way:
public void setUpProfile(Form f) {
Label imageLabel = findMyImage(f);
Image img = getImageFromRes("myprofile.png");
Image scaled = img.scaledWidth(f.getWidth() / 2);
EncodedImage enc = EncodedImage.createFromImage(scaled, false);
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
imageLabel.setIcon(URLImage.createToStorage(enc,
"profileImage8", me.getPicture(), RESIZE_SCALE_WITH_ROUND_MASK));
f.revalidate();
}
});
findProfNameLabel(f).setText(me.getName());
findProfAgeLabel(f).setText(me.getAge() + " Years old");
findProfPrefLabel(f).setText("Interested in " + me.getPref());
}
I am trying to create an image with a given text and style. eg;
" textStyle(Offer ends 25/12/2016. Exclusions Apply., disclaimer) textStyle(See Details,underline) "
In above line i am splitting and creating a map that stores the first parameter of textStyle block as key and second parameter as value where second param defines the style to be applied on first param. Hence an entry of map will look like .
Now when i iterate over this map to write the text to image i check if the text is overflowing the width. If yes then it breaks the text and adds it to next line in the horizontal center. So for example lets say i am trying to write "Offer ends 25/12/2016. Exclusions Apply." with Arial and font size 12. While writing i find that i can write till "Offer ends 23/12/2016. " only and "Exclusions apply" has to go in next line. But it writes the text in horizontal center neglecting that as there is space left horizontally i can write "See Details" too in the same line.
Please help. Below is the code what i have tried. I have also tried creating a JTextPane and then converting it to image but this cannot be an option as it first creates the frame, makes it visible, writes it and then disposes it. And most of the times i was getting Nullpointer exception on SwingUtilities.invokeAndWait.
Actual : http://imgur.com/7aIlcEQ
Expected http://imgur.com/038zQTZ
public static BufferedImage getTextImage(String textWithoutStyle, Map<String, String> textToThemeMap, Properties prop, int height, int width) {
BufferedImage img = new BufferedImage(width,height,BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = img.createGraphics();
g2d.setPaint(Color.WHITE);
FontMetrics fm = g2d.getFontMetrics();
Map<String, Font> textToFontMap = new LinkedHashMap<String, Font>();
for(Map.Entry<String, String> entry : textToThemeMap.entrySet()) {
if(StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
Font font = getFont(prop, entry.getValue().trim());
g2d.setFont(font);
fm = g2d.getFontMetrics();
String string = entry.getKey();
char[] chars = null;
int i = 0, pixelWidth = 0;
List<String> newTextList = new ArrayList<String>();
if(fm.stringWidth(string) > (width - 10)) {
chars = string.toCharArray();
for (i = 0; i < chars.length; i++) {
pixelWidth = pixelWidth + fm.charWidth(chars[i]);
if(pixelWidth >= (width - 10)) {
break;
}
}
String newString = WordUtils.wrap(string, i, "\n",false);
String[] splitString = newString.split("\n");
for(String str : splitString) {
newTextList.add(str);
textToFontMap.put(string, font);
}
} else {
newTextList.add(string);
textToFontMap.put(string, font);
}
}
}
Font font = new Font("Arial", Font.BOLD, 14);
int spaceOfLineHeight = (textToFontMap.size() - 1) * 7;
int spaceOfText = textToFontMap.size() * font.getSize();
int totalSpace = spaceOfLineHeight + spaceOfText ;
int marginRemaining = height - totalSpace;
int tempHt = marginRemaining / 2 + 10;
String txt = null;
for(Map.Entry<String, Font> entry : textToFontMap.entrySet()) {
txt = entry.getKey();
font = entry.getValue();
g2d.setFont(font);
fm = g2d.getFontMetrics();
int x = (width - fm.stringWidth(txt)) / 2;
int y = tempHt;
g2d.drawString(txt, x, y);
tempHt = tempHt + fm.getHeight();
}
// g2d.drawString(text.getIterator(), 0, (int)lm.getAscent() + lm.getHeight());
// g2d.dispose();
return img;
}
// Code with JTextPane ------------------------------------------
public static BufferedImage getTextImage(final Map < String, String > textToThemeMap, final Properties prop, final int height, final int width) throws Exception {
JFrame f = new JFrame();
f.setSize(width, height);
final StyleContext sc = new StyleContext();
DefaultStyledDocument doc = new DefaultStyledDocument(sc);
final JTextPane pane = new JTextPane(doc);
pane.setSize(width, height);
// Build the styles
final Paragraph[] content = new Paragraph[1];
Run[] runArray = new Run[textToThemeMap.size()];
int i = 0;
for (Map.Entry < String, String > entry: textToThemeMap.entrySet()) {
if (StringUtils.isNotBlank(entry.getValue().trim()) && StringUtils.isNotBlank(entry.getKey().trim())) {
Run run = new Run(entry.getValue().trim(), entry.getKey());
runArray[i++] = run;
}
}
content[0] = new Paragraph(null, runArray);
/*createDocumentStyles(sc, prop,textToThemeMap.values());
addText(pane, sc, sc.getStyle("default"), content);
pane.setEditable(false);*/
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
createDocumentStyles(sc, prop, textToThemeMap.values());
} catch (MalformedURLException e) {
//e.printStackTrace();
}
addText(pane, sc, sc.getStyle("default"), content);
pane.setEditable(false);
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
}
f.getContentPane().add(pane);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D gd = img.createGraphics();
f.paint(gd);
f.dispose();
/*ImageIO.write(img, "png", new File("C:\\Users\\spande0\\Desktop\\a.png"));
System.out.println("done");*/
return img;
}
I suspect the issue is in your 'Y' computation.
int spaceOfLineHeight = (newTextList.size() - 1) * 7;
int spaceOfText = newTextList.size() * font.getSize();
int totalSpace = spaceOfLineHeight + spaceOfText;
int marginRemaining = height - totalSpace;
int tempHt = marginRemaining / 2 + 10;
You have to keep the height occupied by the previous lines, and add it to the current 'Y'.
At the moment, for all the lines, the 'Y' values is same.
Declare prevHeight outside the for loop. and then do the following.
int tempHt = marginRemaining / 2 + 10;
tempHT += prevHeight;
prevHeight = tempHeight
Based on the comments, I will suggest you to break down your function into two smaller functions.
// Loop through the strings and find out how lines are split and calculate the X, Y
// This function will give the expected lines
splitLinesAndComputeResult
// Just render the lines
renderLines
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.
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.
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.