Java. Printing high-resolution image without scaling - java

I have a List of java.awt.Image and each of them has a resolution of 300 DPI. I want to print them and when I start to print this images (using javax.PrintService API), printed only piece of some piece of image, because Java's Print/3D classes by default use 72DPI (vs 300 DPI of my images). But when I use images with 72 DPI (with same resolution as the Java default) all images are printed fine (when printing whole images, not only piece of it).
Question: where I can set the printing resolution of my images to fit the printing area?
I tried to set PrintRequestAttributeSet.add( new PrinterResolution(300, 300, ResolutionSyntax.DPI)) but this has no effect.
For now, I scale my images to fit printing area, but after scaling my images I lose quality, so the printed document isn't readable.

You can use drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
Parameters dx1, dy1, dx2 and dy2 define bounds that your image must fit into. You need to do a few calculations. This should print the high quality image on that coordinates (without scaling it down).
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.printImage(....);
return PAGE_EXISTS;
}
}
Then
PrinterJob pj = PrinterJob.getPrinterJob();
...
PageFormat pf = ...;
...
pj.setPrintable(new MyPrintable(), pf);
You still need to set the resolution as you did before.

Related

Scaling an image with Java

I create an image that is an extract of a PDF and i make an OCR with tesseract on it. Everything works good until a decide to change the dpi of my image. I was excpecting to have an error by doing this and i tried to rescale my image in order to make my OCR work well again.
I have no idea about how I can rescale my image. I know there is some methods with the BufferedImage class but i can't find a way to dynamicly rescale it.
I don't know if I'm clear but imagine a 300 dpi image. If I want to change it to 600 I have to rescale my image to make my OCR work again, my question here is how can I rescale it dynamicly ? Is there a sort of a ratio between the original dpi and the new one that i can use to get a new width and height? Or something else?
To help you understand me here is my code:
public double ratioDPI() {
int ratio = 0;
int minimal_dpi = 300;
int dpi = ERXProperties.intForKey("dpi.image");
return ratio = (dpi/minimal_dpi);
}
public BufferedImage rescale(BufferedImage img) {
int width_img = img.getWidth();
int height_img = img.getHeight();
double factor_width = ERXProperties.doubleForKey("factor.size.width.image.republique.francaise");
double factor_height = ERXProperties.doubleForKey("factor.size.height.image.republique.francaise");
return (BufferedImage) img.getScaledInstance((int)(width_img*ratio), (int)(height_img*ratio), BufferedImage.SCALE_SMOOTH);
}
If you change the DPI of an image, you change the size when outputting it to a printer, for example. If you increase the DPI from 300 to 600, the image in the output only takes up half the width and half the height. If you resize the picture now it only takes up more memory, the quality of the picture would not be better.
For scaling it is best to use AffineTransform, so you can filter the image bilinear so that the pixelation is not so noticeable:
A scaling function:
public static BufferedImage scale(BufferedImage source, double scale, boolean bilinearFiltering){
try{
BufferedImage destination = new BufferedImage((int)(source.getWidth() * scale), (int)(source.getHeight() * scale), source.getType());
AffineTransform at = new AffineTransform();
at.scale(scale, scale);
AffineTransformOp scaleOp = new AffineTransformOp(at, getInterpolationType(bilinearFiltering));
return scaleOp.filter(source, destination);
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static int getInterpolationType(boolean bilinearFiltering){
return bilinearFiltering ? AffineTransformOp.TYPE_BILINEAR : AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
}
Maybe that's a solution for you.

Is cropping and rescaling background a good solution for java games?

I'm very new to java and I'm currently developping a 2D game.
I'm trying to use Java Swing for the graphics and I have a problem doing so :
Displaying the background, which is a fairly high definition image, (currently 2000x2000 but will grow bigger for higher definition), with a map of 50 units in width and height.
The problem is that I don't want to display the whole map but only a fixed amount of cells in width and height of it (here i chose 20). I first tried to rescale the image wider than the screen to make the 20 cells fit perfectly (a bit like a zoom on the area we want) and then draw it with an offset related to the player's position (which is always displayed on the centered of the screen).
But while i try to go with bigger images, i get a java heap space memory exception.
So i was thinking of getting a cropped version of the image and then rescale it to the screen's dimension to have a smaller rescaled image. I'm not getting exceptions any more but I have some important performances issues with a drop of 30 fps.
I was also thinking about getting all cropped images possible and storing them but I wanted to know if that's a thing or not.
To sum up, I was wondering what were the best ways to display a background in games.
Since 2D games or even 3D games have maps even larger than I do, I think I must be missing something, I don't get how to display sprites with high resolution while keeping a decent frame rate.
Thank your for your time.
edit:
To put a bit of context : The map is a big maze and the player should only be able to see a local view of the maze. And because I would want a rather detailed Background, i have to be able to display large images.
Here is a reduced view of my code sample :
public class Background implements Drawable, Anchor {
private final String name;
private final Image image;
private final int width;
public Background(String name){
this.name = name;
BufferedImage image = FileSystem.readBufferedImage(GraphicType.BACKGROUND, name);
//image is a 2000x2000 image
this.image = image.getScaledInstance((int)(behavior.width()
* (Game.frame.getWidth()/(double) Settings.NB_CELLS_ON_SCREEN_WIDTH)),
-1,
0
);
//result in a 19200x19200 image
this.width = (int)(behavior.width()
* (Game.frame.getWidth()/(double)Settings.NB_CELLS_ON_SCREEN_WIDTH));
}
#Override
public void draw(Graphics g) {
g.drawImage(
image,
-8640,
-9060,
null);
}
}
With the GraphicPosition class computing the position on screen, with the following arguments in constructor : An anchor object, an xOffset and a yOffset
I now draw the background using the drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
As matt suggested, it causes a less significant fps drop because i'm no longer creating a huge temporary image and the good thing about this solution is that the difference in frame rate with bigger images seems to be small.
Here is the code I used and worked for me :
public class Foreground implements Drawable {
private final String name;
private final BufferedImage image;
private final Behavior behavior;
private final int width;
public Foreground(String name, Behavior behavior){
this.name = name;
this.image = FileSystem.readBufferedImage(GraphicType.FOREGROUND, name);
this.behavior = behavior;
}
#Override
public void draw(Graphics g) {
/*This variable represents the width on the image of the number of cells
In my code its is the width on the image of 20 cells*/
int widthOnImageForNbCellsDisplayed = (image.getWidth()/behavior.width()) * Settings.NB_CELLS_ON_SCREEN_WIDTH;
/*This posXInImage represents the position of the top left corner of the
area of the image we want to draw*/
int posXInImage = (int)(
Game.player.posX()
* image.getWidth()
/ (double)behavior.width()
- widthOnImageForNbCellsDisplayed/2
);
int posYInImage = (int)(
Game.player.posY()
* image.getHeight()
/ (double)behavior.height()
- widthOnImageForNbCellsDisplayed/2
);
/*Here is struggled with the fact that the position of the second
coordinates is absolute and not relative to the first coordinates
,what I was originally thinking*/
g.drawImage(image,
0,
-(Game.frame.getWidth() - Game.frame.getHeight())/2,
Game.frame.getWidth(),
Game.frame.getWidth()-(Game.frame.getWidth() - Game.frame.getHeight())/2,
posXInImage,
posYInImage,
posXInImage + widthOnImageForNbCellsDisplayed,
posYInImage + widthOnImageForNbCellsDisplayed,
null);
}
}

JPanel distorted scaling issue

Description: I am writing a small program that needs to generate a report (1 pager). This is nothing big and it's the first time I need to generate some sort of report as a printable output. Should be simple enough, so I created a JPanel, added all the fields/panels and styles required to make it look like a report.
Problem: When I try to print the report it does not fit on an A4 and is cuts off at the right and bottom. I then tried to change the print method to scale the JPanel but now I am getting some strange compression (right word?) issues on the font and some other items.
What I've tried: I tried to print the report to a JPEG/PNG (This looks perfect when viewed) and then send to the printer but this causes horrible image quality issues. I then changed the JPanel contents to be smaller to fit but this made the report look to small when viewed on the screen before printing.
Help with: It would be nice if someone could point me in the right direction or tell me where my scaling is causing the issue if possible... I really do not look forward to creating different panels for each report just to view and print correctly.
public int print(Graphics gc, PageFormat pageFormat, int pageIndex) {
if(pageIndex>0) {
return NO_SUCH_PAGE;
}
// Create a instance of the RepaintManager from the component being printed
RepaintManager mgr = RepaintManager.currentManager(component);
Graphics2D g2d = (Graphics2D)gc;
// Get the bounds of the component
Dimension dim = component.getSize();
double cHeight = dim.getHeight();
double cWidth = dim.getWidth();
// Get the bounds of the printable area
double pHeight = pageFormat.getImageableHeight();
double pWidth = pageFormat.getImageableWidth();
double pXStart = pageFormat.getImageableX();
double pYStart = pageFormat.getImageableY();
double xRatio = pWidth / cWidth;
double yRatio = pHeight / cHeight;
g2d.scale(xRatio, yRatio);
mgr.setDoubleBufferingEnabled(false); // Only for swing components
component.paint(g2d);
mgr.setDoubleBufferingEnabled(true); // Only for swing components
return PAGE_EXISTS;}

How can I scale my bitmap in Android based on the width and height pixels?

I want to be able to scale my image based on the screen size. In a normal java applet I would do something like the following....
int windowWidth = 1280;
int windowHeight = 720;
Image image;
public void paint(Graphics g)
{
g.drawImage(image, x, y, windowWidth / 4, windowHeight / 16, null);
}
I've been searching for an answer for a while and everything I find seems to turn up some weird result. From what I read I might need to do something with Resolution Independent Pixels but I'm not %100 sure.
The thing I am trying to avoid is having to create a whole new set of images and icons just for different screen densities. The method I showed above works for resizing desktop apps without a problem.
Edit:
This is what I have been using to draw an image in android.
Matrix matrix = new Matrix();
Bitmap image;
Constuctor....()
{
image = BitmapFactory.decodeResource(context.getResources(), R.drawable.play);
}
public void render(Canvas c)
{
c.drawBitmap(image, matrix, null);
}
Hi see thsi question I have posted scale bitmap
If you are using canvas get the width and height of the canvas. or if you want to have it formal normal layouts then get the width and height by using
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
dispWidth=metrics.widthPixels;
dispheight=metrics.heightPixels;
and then scale our bitmap according to your requirement like this. In this I Have to have 8 bricks so I have taken the width by dividing with the Number of columns
String strwidth=String.valueOf(((float)(bmp.getWidth())/NO_COLUMNS));
if(strwidth.contains("."))
{
scalebit=Bitmap.createScaledBitmap(bmp, (int)(Math.ceil(((float)bmp.getWidth())/NO_COLUMNS))*NO_COLUMNS, bmp.getHeight(), true);
}
else
{
scalebit=bmp;
}

Why won't my image display in my Java Applet?

When I use the following code:
public void paint(Graphics g){
//Displays version number and name.
g.setFont(new Font("Courier", Font.PLAIN, 10));
g.drawString("DCoder " + execute.Execute.version, 2, 10);
//Displays logo in center.
g.drawImage(logo, centerAlign(logo.getWidth(null)), 50, this);
}
private int width(){
//Gets and returns width of applet.
int width = getSize().width;
return width;
}
private int height(){
//Gets and returns height of applet.
int height = getSize().height;
return height;
}
private int centerAlign(int obWidth){
int align = (width()-obWidth)/2;
return align;
}
in my Java Applet, the image will not display until I call repaint() (by resizing the Applet Viewer window)? Why won't the image display?
An asynchronous loaded image has to be handled thus.
logo.getWidth(this); // Indicate asynchronous ImageObserver
...
#Override
public boolean imageUpdate(Image img,
int infoflags,
int x,
int y,
int width,
int height) {
if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
// The image is entirely read.
repaint();
}
}
When asynchronous reading an image, getWidth(null) will return 0 till the width is determined etcetera. Therefore one needs to be a bit careful.
Explanation
Loading images was designed to be done asynchronously. The Image is already available, but before being read getWidth and/or getHeight is -1. You can pass an ImageObserver to getWidth/getHeight, which is then notified during the image reading. Now JApplet already is an ImageObserver, so you can just pass this.
The reading code will the passed/registered ImageObserver's method imageUpdate to signal a change; that the width is known, that SOMEBITS (= not all), so one could already draw a preview, like in a JPEG pixelized preview.
This asynchrone technique was in the earlier days of the slow internet needed.
If you want to read an image simpler, use ImageIO.read(...).
Why won't the image display?
Most probably because it was loaded using an asynchronous method.

Categories