Java PrinterJob, high quality printing ends up with 72 DPI anyway - java

I am trying to print an image on 1 inch x 2 inch label with 300 dpi printing quality
public void print() {
RepaintManager currentManager = RepaintManager.currentManager(this);
currentManager.setDoubleBufferingEnabled(false);
PrinterJob job = PrinterJob.getPrinterJob();
try {
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
set.add(PrintQuality.HIGH);
set.add(MediaSize.findMedia(2.125f, 1f, MediaSize.INCH));
// 2" x 1" PrintableArea
set.add(new MediaPrintableArea(1f/16f, 0f, 2.0f, 1f, MediaPrintableArea.INCH));
set.add(new PrinterResolution(300, 300, ResolutionSyntax.DPI));
set.add(OrientationRequested.PORTRAIT);
job.setPrintable(this);
job.setJobName("Label");
job.print(set);
} catch (PrinterException e) {
// The job did not complete successfully
e.printStackTrace();
}
currentManager.setDoubleBufferingEnabled(true);
}
My BufferedImage is 300 x 600 pixels which should fit
BufferedImage bi = freeze(this); //getting BufferedImage from JPanel
System.out.println("Image dim: "+bi.getWidth()+" X "+bi.getHeight());
Console output: Image dim: 600 X 300.
But the problematic part is when i print out Imageable dimensions like
double x=pf.getImageableX();
double y=pf.getImageableY();
int w = (int)Math.round(pf.getImageableWidth());
int h = (int)Math.round(pf.getImageableHeight());
System.out.println("X: "+x);
System.out.println("Y: "+y);
System.out.println("W: "+w);
System.out.println("H: "+h);
the out put is:
X: 4.50141716003418
Y: 0.0
W: 144
H: 72
from h & w: I'm left with 72 pixel per inch here, and any resizing has no effect, this make no sense,
what is the useful of HashPrintRequestAttributeSet request for 300 DPI ?

The API docs of PageFormat#getImageableHeight() clearly says:
Return the height, in 1/72nds of an inch, of the imageable area of the page. This method takes into account the orientation of the page.
(The API docs of getImageableWidth() is similar.)
As you specified the printable area to be 2x1 inch (see MediaPrintableArea attribute in your code), the imageable width and height is 144 resp. 72 (1/72nds of an inch).
There is no single word in the method docs about DPIs.

The magic just happened, thanks to "Marty Hall" for this Tutorial "Printing Swing Components in Java 1.2"
what i did is:
1- don't implement the printable interface on the same panel you want to print
2- Use a utility class (mentioned in the tutorial to do the job)
3- Use one graphic object to draw all the component (position images), don't stack/layout many components to paint the panel
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHints(rh);
// Grids for testing porpose
for(int i=50; i<=300; i+=50) {
g2d.drawLine(i, 0, i, 600);
g2d.drawString(""+i, i-20,20);
}
for(int i=100; i<=400; i+=100) {
g2d.drawLine(0, i, 300, i);
g2d.drawString(""+i, 10,i-10);
}
g2d.translate(0, 400);
BufferedImage barcodeImage=getBarCode128(String.valueOf(1234567));
g2d.drawImage(barcodeImage, 0, 0, 300, 200, null);
}
4- added HashPrintRequestAttributeSet to the print() method as "Marty Hall" class uses printDialog() to do that, which wasn't applicable for me
public void print() {
PrinterJob printJob = PrinterJob.getPrinterJob();
HashPrintRequestAttributeSet set = new HashPrintRequestAttributeSet();
set.add(PrintQuality.HIGH);
set.add(MediaSize.findMedia(1f, 2.125f, MediaSize.INCH));
set.add(new MediaPrintableArea(0f, 1f/16f, 1f, 2.0f, MediaPrintableArea.INCH));
set.add(new PrinterResolution(300, 300, ResolutionSyntax.DPI));
set.add(OrientationRequested.PORTRAIT);
printJob.setPrintable(this);
try {
printJob.print(set);
} catch(PrinterException pe) {
System.out.println("Error printing: " + pe);
}
}
5-Do the translate and scale as desired then print the panel
public int print(Graphics g, PageFormat pf, int pageIndex) {
if (pageIndex > 0) {
return(NO_SUCH_PAGE);
} else {
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
g2d.scale(pf.getImageableWidth()/componentToBePrinted.getWidth(), pf.getImageableHeight()/componentToBePrinted.getHeight());
disableDoubleBuffering(componentToBePrinted);
componentToBePrinted.paint(g2d);
enableDoubleBuffering(componentToBePrinted);
return(PAGE_EXISTS);
}
}
the final result is high resolution image readable barcode

Related

How can I set the origin of a component I'm trying to make into a JLabel from top-left to bottom-left?

I'm trying to make a 2D sprite game, and as of now, the JLabel on which the image draws starts at the top left. This presents a problem when I try to move the sprite laterally because if the sprite that's supposed to come next is taller than the previous, it won't be standing on the floor as it should. In this picture, the left is the starting, the middle is what it does now with the top-left as 0,0, and the right is what it should be, screen-grabbed from the actual game.
below is my paint for the model of Mario:
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(sprite, 0,0, null);
}
and below is my paintComponent that's in a class that when run, renders the image onto the screen:
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
marioSprite.paint(g2);
}
and how I extract an image from a file:
//generate URL
public static URL urlGenerator(String name){
URL u = lookup().lookupClass().getResource(name);
return u;
}
//return image with filtered color
public static BufferedImage generateAndFilter(BufferedImage b, URL u){
try{
b = ImageIO.read(u);
int width = b.getWidth();
int height = b.getHeight();
int[] pixels = new int[width * height];
b.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
if (pixels[i] == 0xFFff00fe) {
pixels[i] = 0x00ff00fe;
}
}
BufferedImage newSprite = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
newSprite.setRGB(0, 0, width, height, pixels, 0, width);
b = newSprite;
}
catch(IOException e){
System.out.println("sprite not found");
e.printStackTrace();
}
return b;
}
each instance of Mario has a sprite set by:
public void setSprite(String spriteName){
URL spriteAtLoc = Utils.urlGenerator(spriteName);
this.sprite = Utils.generateAndFilter(sprite,spriteAtLoc);
this.currentSpriteName = spriteName;
}

JavaFX Printable to Image very pix-elated, but perfect to printer

I have a printable object that prints perfectly fine to a printer, but when i print it to an Image, then it is very pixelated?
Here is my code to setup a printer for printing and to an image
private PageFormat setupPrinter() {
// sizing (standard is 72dpi, so multiple inches by this)
Double height = 4d * 72d;
Double width = 3d * 72d;
Double margin = 0.1d * 72d;
// now lets print it
AttributeSet attributes = new HashAttributeSet();
attributes.add(new Copies(1));
PrinterJob printJob = PrinterJob.getPrinterJob();
PageFormat pageFormat = printJob.defaultPage();
// if there are more than 10 items, up the paper size to 6inch.
// This will handle up to 24 different items
if (1 == 2) height = 6d * 72d;
// set page size
Paper paper = pageFormat.getPaper();
paper.setSize(width, height);
paper.setImageableArea(margin, margin, width - (margin * 2), height - (margin * 2));
// set orientation and paper
pageFormat.setOrientation(PageFormat.PORTRAIT);
pageFormat.setPaper(paper);
return pageFormat;
}
private void printToImage() {
MyPrintable myPrintable = new MyPrintable();
// setup our printer
PageFormat pageFormat = setupPrinter();
// set size of imageView, using the hieght and width values
double imageHeight = pageFormat.getHeight();
double imageWidth = pageFormat.getWidth();
// create our image/graphics
BufferedImage image = new BufferedImage((int)imageWidth, (int)imageHeight, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.getGraphics();
// color background white
graphics.setColor(Color.WHITE);
((Graphics2D) graphics).fill(new Rectangle.Float(0, 0, (float)imageWidth, (float)imageHeight));
// directly call our print method, passing graphics, pageFormat and pageIndex
try {
myPrintable.print(graphics, pageFormat, 0);
} catch (PrinterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
graphics.dispose();
// set our image
imgReport.setImage(SwingFXUtils.toFXImage(image, null));
// now lets show the preview pane
reportPane.setVisible(true);
}
public void printToPrinter(ActionEvent event) {
PrinterJob printJob = PrinterJob.getPrinterJob();
PageFormat pageFormat = setupPrinter();
printJob.setPrintable(new MyPrintable(), pageFormat);
try {
printJob.print();
} catch (Exception e) {
e.printStackTrace();
}
}
public MyPrintable() {
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
if (pageIndex > 0) {
return NO_SUCH_PAGE;
}
// user (0,0) is typically outside the imageable area, so we must translate
// by the X and Y values in the pageFormat to avoid clipping
Graphics2D g2d = (Graphics2D) graphics;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
// add text etc here
........
}
}
Here is an example of how pixelated it is. Bit it fits in the image perfectly....
You can use a controlling rendering quality
read this:
https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html
example for your code:
Graphics2D graphics = (Graphics2D)image.getGraphics();
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHints(rh);
graphics.setColor(Color.WHITE);
graphics.fill(new Rectangle.Float(0, 0, (float)imageWidth, (float)imageHeight));

How can I rotate an onscreen component in Java?

import javax.swing.*;
import java.awt.*;
public class JFrameAnimationTest extends JFrame {
public static void main(String[] args) throws Exception{
AnimationPanel animation = new AnimationPanel();
JFrameAnimationTest frame = new JFrameAnimationTest();
frame.setSize(600, 480);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(animation);
frame.setVisible(true);
for(int i = 0; i < 100; i++) {
animation.incX(1);
//animation.incY(1);
animation.repaint();
Thread.sleep(10);
}
}
}
class AnimationPanel extends JPanel {
int x = 10;
int y = 10;
public AnimationPanel() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(x, y, 20, 20);
g.fillRect(x, y, 20, 20);
}
protected void incX(int X) {
x += X;
}
protected void incY(int Y) {
y += Y;
}
}
So anyways theres my code. It probably looks a bit jumbled as I am not used to stackoverflow just yet so I apologize.
Here's my question: This program makes this small rectangle slowly move to the right; how can I add rotation to the rectangles movement during that time period?
Note: I haven't actually compiled this code, but you get the gist.
public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2d = (Graphics2D) g;
// The 20x20 rectangle that you want to draw
Rectangle2D rect = new Rectangle2D.Double( 0, 0, 20, 20 );
// This transform is used to modify the rectangle (an affine
// transform is a way to do operations like translations, rotations,
// scalings, etc...)
AffineTransform transform = new AffineTransform();
// 3rd operation performed: translate the rectangle to the desired
// x and y position
transform.translate( x + 10, y + 10 );
// 2nd operation performed: rotate the rectangle around the origin
transform.rotate( rotation );
// 1st operation performed: translate the rectangle such that it is
// centered on the origin
transform.translate( -10, -10 );
// Apply the affine transform
Shape s = transform.createTransformedShape( rect );
// Fill the shape with the current paint
g2d.fill( s );
// Stroke the edge of the shape with the current paint
g2d.draw( s );
}
Also note that you should really be using something like a javax.swing.Timer when you modify x, y, and rotation and when you call repaint(). That way all of it happens on the event dispatch thread.

JPanel repaint from another class

I have a JPanel which displays an image. In a separate class, I'm reading from an xml file points. I am firstly creating an arraylist of triangles from these points. However I need to show the triangles on the image, i.e. draw them on! (yes this should be simple). But as these points and triangles are created in another class, I do not seem to be able to draw them on the already-displayed image within the GUI class. I have tried creating a ArrayList in the JPanel itself, which I update and then want to repaint, although it will not let me do this as shown below:
Class
triangles = clips.getTriangles();
tempPanel.setTriangles(triangles){
JPanel
public void settriangles(ArrayList<Point[]> t){
triangles = t;
repaint();
}
My only other idea is for the JPanel to have a listener waiting for when triangles are returned, updating the field and hence then repainting.
Any ideas?
Thanks
Edit: Code for Drawing
public void settriangles(ArrayList<Point[]> t){
triangles = t;
repaint();
}
public void paintComponent(Graphics g) {
System.out.println("in paint component");
if (g != null) {
Graphics2D graphics = (Graphics2D) g;
try {
Rectangle back_rect = new Rectangle(0, 0, getWidth(),
getHeight());
graphics.setColor(GuiComponentGenerator.GUI_BACKGROUND_COLOUR);
graphics.fill(back_rect);
if (image != null) {
int width = Math.round(image.getWidth() * magnification);
int height = Math.round(image.getHeight() * magnification);
Rectangle image_rect = new Rectangle(offset.x, offset.y,
width, height);
graphics.setColor(Color.BLACK);
graphics.draw(image_rect);
graphics.drawImage(image, offset.x, offset.y, width,
height, null);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for(int pos = 0; pos < triangles.size(); pos++){
Point[] current = triangles.get(pos);
ArrayList<Point> current_triangle = new ArrayList<Point>();
current_triangle.add(current[0]);
current_triangle.add(current[1]);
current_triangle.add(current[2]);
drawRegion(graphics, current_triangle);
}
}
}
finally {
graphics.dispose();
}
}
private void drawRegion(Graphics2D graphics, ArrayList<Point> points) {
graphics.setColor(trans_grey);
Area area = getArea(points);
graphics.fill(area);
graphics.setStroke(new BasicStroke(2));
graphics.setColor(Color.BLACK);
graphics.draw(area);
}
private Area getArea(ArrayList<Point> points) {
Area area = new Area(getPath(points, true));
return area;
}
private GeneralPath getPath(ArrayList<Point> points, boolean close_path) {
GeneralPath path = new GeneralPath();
Point current_screen_point = calculateScreenPoint(points.get(0));
path.moveTo(current_screen_point.x, current_screen_point.y);
for (int point_num = 1; point_num < points.size(); point_num++) {
current_screen_point = calculateScreenPoint(points.get(point_num));
path.lineTo(current_screen_point.x, current_screen_point.y);
}
if (close_path)
path.closePath();
return path;
}
public Point calculateScreenPoint(Point image_point) {
float h_proportion = (float) image_point.x / (float) image.getWidth();
float v_proportion = (float) image_point.y / (float) image.getHeight();
float image_width_in_panel = (float) image.getWidth() * magnification;
float image_height_in_panel = (float) image.getHeight() * magnification;
Point on_screen_point = new Point(0, 0);
on_screen_point.x = offset.x
+ Math.round(h_proportion * image_width_in_panel);
on_screen_point.y = offset.y
+ Math.round(v_proportion * image_height_in_panel);
return on_screen_point;
}
Your paintComponent leaves a little to be desired ;)
Firstly, you should never get a null graphics unless the paint method has been called in correctly, which in case they deserve for it to fail.
You should try and use Graphics.create to create a copy of the incoming Graphics context. This allows you to mess with the Graphics properties (such as transforms etc) without adversly effecting the original
I don't know what the image is all about, but basically, if its null, your triangles will never paint (don't know if this is what you want or not).
I don't know what the offset relates to, but just in case, the 0x0 point is always the top, left corner of your component.
public void paintComponent(Graphics g) {
// This is important, you will to have a very good reason not to call this
super.paintComponent(g);
System.out.println("in paint component");
// Should never need this. You should never call the paintComponent
// directly.
// if (g != null) {
// Create a copy of the graphics, with which you can play...
Graphics2D graphics = (Graphics2D) g.create();
try {
Rectangle back_rect = new Rectangle(0, 0, getWidth(),
getHeight());
graphics.setColor(Color.GREEN);
graphics.fill(back_rect);
// What's this trying to do...
// Where do you produce this???
// Because I didn't know where the image was been produced
// I commented out the code, but you should be aware
// That if the image is null, you triangles will never paint...
// if (image != null) {
// int width = Math.round(image.getWidth() * magnification);
// int height = Math.round(image.getHeight() * magnification);
//
// Rectangle image_rect = new Rectangle(offset.x, offset.y,
// width, height);
// graphics.setColor(Color.BLACK);
// graphics.draw(image_rect);
// graphics.drawImage(image, offset.x, offset.y, width,
// height, null);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (int pos = 0; pos < triangles.size(); pos++) {
Point[] current = triangles.get(pos);
ArrayList<Point> current_triangle = new ArrayList<Point>(3);
current_triangle.add(current[0]);
current_triangle.add(current[1]);
current_triangle.add(current[2]);
drawRegion(graphics, current_triangle);
}
//} // From the image != null
} finally {
graphics.dispose();
}
}
I'd also suggest you have a read through
2D Graphics
Performing Custom Painting in Swing
If you haven't already ;)
This article will give you all the info you need http://java.sun.com/products/jfc/tsc/articles/painting/
but I think you are missing -
super.paintComponent(g);
public class MyPanel extends JPanel {
protected void paintComponent(Graphics g) {
// Let UI delegate paint first
// (including background filling, if I'm opaque)
super.paintComponent(g);
// paint my contents next....
}
}
I worked out how to draw triangles on the image, when passing through an arrayList, where each Point[] represents the points of the triangle.
Note that this is now in a single entire class which is passed the information, rather than trying to call repaint from another class.
public AnnotatedDisplayTriangles(BufferedImage image, String image_path, ArrayList<Point[]> triangles) {
this.image = image;
this.image_path = image_path;
this.triangles = triangles;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw image centered.
int x = (getWidth() - image.getWidth())/2;
int y = (getHeight() - image.getHeight())/2;
g.drawImage(image, x, y, this);
Stroke drawingStroke = new BasicStroke(2);
Graphics2D graph = (Graphics2D)g;
graph.setStroke(drawingStroke);
graph.setPaint(Color.black);
for(int p = 0; p < triangles.size(); p++){
Point[] current_triangles = triangles.get(p);
for(int triangle = 0; triangle < current_triangles.length; triangle++ ){
Point current = current_triangles[triangle];
Point next;
if(triangle == current_triangles.length -1 )
next = current_triangles[0];
else
next = current_triangles[triangle + 1];
Line2D line = new Line2D.Double(current.x, current.y, next.x, next.y);
graph.draw(line);
}
}
}
public static void main(String image_path,ArrayList<Point[]> triangles, String panel_name) throws IOException {
String path = image_path;
BufferedImage image = ImageIO.read(new File(path));
AnnotatedDisplayTriangles contentPane = new AnnotatedDisplayTriangles(image, path, triangles);
// You'll want to be sure this component is opaque
// since it is required for contentPanes. Some
// LAFs may use non-opaque components.
contentPane.setOpaque(true);
int w = image.getWidth();
int h = image.getHeight();
JFrame f = new JFrame(panel_name);
// f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(contentPane);
f.setSize(w,h);
f.setLocation(200,200);
f.setVisible(true);
}

Drawing multiple lines in a BufferedImage

I am trying to draw horizontal and vertical lines on a bufferedimage. It should end up looking like a grid of cells. But when I run the code, I see only two lines: the leftmost line and the topmost line (ie. a line from 0,0 to 0,height of image & 0,0 to width of image,0) Heres the code snippet:
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.BLACK);
BasicStroke bs = new BasicStroke(2);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
g2d.drawLine((imgDim.width+2)*i, 0, (imgDim.width+2)*i, imgDim.height-1);
g2d.drawLine(0, (imgDim.height+2)*i, imgDim.width-1, (imgDim.height+2)*i);
}
And the overriden paint method:
public void paint(Graphics g) {
g.drawImage(mazeImage, 0, 0, this);
}
This is all in a class called RobotMaze that extends JPanel. Any help is appreciated.
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
class GridLines {
public static void main(String[] args) {
Dimension imgDim = new Dimension(200,200);
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.BLACK);
BasicStroke bs = new BasicStroke(2);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
// unless divided by some factor, these lines were being
// drawn outside the bound of the image..
g2d.drawLine((imgDim.width+2)/20*i, 0, (imgDim.width+2)/20*i,imgDim.height-1);
g2d.drawLine(0, (imgDim.height+2)/20*i, imgDim.width-1, (imgDim.height+2)/20*i);
}
ImageIcon ii = new ImageIcon(mazeImage);
JOptionPane.showMessageDialog(null, ii);
}
}
Print out your coordinates and you will see that you are plotting points outside the width and height of the image:
System.out.printf("Vertical: (%d,%d)->(%d,%d)\n",(imgDim.width+2)*i, 0, (imgDim.width+2)*i, imgDim.height-1);
System.out.printf("Horizontal: (%d,%d)->(%d,%d)\n",0, (imgDim.height+2)*i, imgDim.width-1, (imgDim.height+2)*i);
How do you expect the result of (imgDim.width+2)*i to be within the image boundaries if i > 0?

Categories

Resources