Improving image quality for Tesseract Tess4j? - java

On the website where I screenshoted the image the numbers will change continuously.
What I'm trying to do is to read the image text(which is numbers, dot and X on the image) using Tesseract, tess4j java.
The problem is I'm getting inconsistent results, sometimes I get letters sometimes letters with numbers.
After I blacklisted letters excerpts the letter X and special character . I now get 4.0 if I'm not getting the correct results from the picture.
I added a code below to GrayScale the image but still I'm getting the same inconsistent results.
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
public class GrayScalingImage {
public static void main(String args[]) throws Exception {
try {
File inputImage = new File("image.jpg"); BufferedImage image = ImageIO.read(inputImage);
for(int i=0; i<image.getHeight(); i++) {
for(int j=0; j<image.getWidth(); j++) {
Color color = new Color(image.getRGB(j, i));
int red = (int)(color.getRed() * 0.299);
int green = (int)(color.getGreen() * 0.587);
int blue = (int)(color.getBlue() * 0.114);
Color newColor = new Color(red+green+blue, red+green+blue,red+green+blue);
image.setRGB(j, i, newColor.getRGB());
}
}
File ouptut = new File("newImage.jpg"); ImageIO.write(image, "jpg", ouptut);
}
catch (Exception e) {
}
}
}

Related

BufferedImage -> int[] -> BufferedImage result in greyed black

I am doing some basic experimentation on picture filtering using convolution matrix, based on the Wikipedia page about kernels in image processing.
In order to compute the RGB transformations, I am reading the bitmap via a BufferedImage then get the pixels with getRgb(). While testing the simplest identity filter I noticed that for a specific picture I was getting some grey instead of the original black, while for some other picture, the black was OK.
After more testing, I found that without any transform, a simple BufferedImage -> int[] -> BufferedImage results in the greyed result.
What am I missing ? ImageMagick identify shows that both are 8-bit 256 colors pictures without alpha channels.
betty1.png PNG 339x600 339x600+0+0 8-bit Gray 256c 24526B 0.000u 0:00.000
betty2.jpg JPEG 603x797 603x797+0+0 8-bit Gray 256c 126773B 0.000u 0:00.001
With this picture the result is as expected.
With this one, the result is unexpectedly greyed.
Here is a simple sscce test class to show the problem:
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
/* simple test class for convolution matrix */
public class CopyPic {
public static void main(String args[]) throws FileNotFoundException, IOException {
if (args.length < 1) {
System.err.println("Usage: CopyPic <picture_file>");
System.exit(1);
}
String imgPath = args[0];
String inputName = imgPath.substring(0, imgPath.lastIndexOf("."));
File ifile = new File(imgPath);
InputStream fis_in = new FileInputStream(ifile);
BufferedImage bi_in = ImageIO.read(fis_in);
fis_in.close();
int width = bi_in.getWidth();
int height = bi_in.getHeight();
System.out.println(String.format("%s = %d x %d", imgPath, width, height));
int[] rgb_in = new int[width * height];
bi_in.getRGB(0, 0, width, height, rgb_in, 0, width);
BufferedImage bi_out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// for (int y = 0; y < height; y++) {
// for (int x = 0; x < width; x++) {
// bi_out.setRGB(x, y, rgb_out[y * width + x]);
// }
// }
bi_out.setRGB(0, 0, width, height, rgb_in, 0, width);
display(bi_in, bi_out);
String outputName = inputName + "-copy.png";
File ofile = new File(outputName);
OutputStream fos_out = new FileOutputStream(ofile);
ImageIO.write(bi_out, "PNG", fos_out);
fos_out.flush();
fos_out.close();
System.out.println("Wrote " + outputName);
}
// use that to have internal viewer
private static JFrame frame;
private static JLabel label1, label2;
private static void display(BufferedImage img1, BufferedImage img2) {
if (frame == null) {
frame = new JFrame();
frame.setTitle(String.format("%dx%d Original / Copy", img1.getWidth(), img1.getHeight()));
frame.setSize(img1.getWidth() + img2.getWidth(), img1.getHeight());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
label1 = new JLabel();
label1.setIcon(new ImageIcon(img1));
frame.getContentPane().add(label1, BorderLayout.WEST);
label2 = new JLabel();
label2.setIcon(new ImageIcon(img2));
frame.getContentPane().add(label2, BorderLayout.EAST);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
} else {
label1.setIcon(new ImageIcon(img1));
label2.setIcon(new ImageIcon(img2));
}
}
}
When the ImageIO.read function creates a BufferedImage it uses the type that it thinks is best suited. This type might not be what you expect. In particular, for a JPG image the type might not be TYPE_INT_ARGB.
This is the case for your second image and becomes evident when you print the type of that image:
System.out.println(bi_in.getType());
For that image, this prints 10 on my machine, which represents TYPE_BYTE_GRAY.
So, to fix your problem you should use:
BufferedImage bi_out = new BufferedImage(width, height, bi_in.getType());

YOLO...Program doesnt go through the loop to analyze each frame

Recently I am trying to implement an image object detection tool based on YOLO. To start with, I have used the codes here. Things sounds fine except the fact the program doesnt pass the following line of code (line 72) and will not go into the loop. :
if (cap.read(frame))
In other words, if a break point is placed at that line, the program wont go to next step.. Any idea how to fix this?
package yoloexample;
import org.opencv.core.*;
import org.opencv.dnn.*;
import org.opencv.utils.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Yoloexample {
private static List<String> getOutputNames(Net net) {
List<String> names = new ArrayList<>();
List<Integer> outLayers = net.getUnconnectedOutLayers().toList();
List<String> layersNames = net.getLayerNames();
outLayers.forEach((item) -> names.add(layersNames.get(item - 1)));//unfold and create R-CNN layers from the loaded YOLO model//
System.out.println(names);
return names;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
System.load("\\opencv\\opencv\\build\\java\\x64\\opencv_java420.dll"); // Load the openCV 4.0 dll //
String modelWeights = "g:\\yolov3.weights"; //Download and load only wights for YOLO , this is obtained from official YOLO site//
String modelConfiguration = "g:\\yolov3.cfg";//Download and load cfg file for YOLO , can be obtained from official site//
String filePath = "test.mp4"; //My video file to be analysed//
VideoCapture cap = new VideoCapture(filePath);// Load video using the videocapture method//
Mat frame = new Mat(); // define a matrix to extract and store pixel info from video//
//cap.read(frame);
JFrame jframe = new JFrame("Video"); // the lines below create a frame to display the resultant video with object detection and localization//
JLabel vidpanel = new JLabel();
jframe.setContentPane(vidpanel);
jframe.setSize(600, 600);
jframe.setVisible(true);// we instantiate the frame here//
Net net = Dnn.readNetFromDarknet(modelConfiguration, modelWeights); //OpenCV DNN supports models trained from various frameworks like Caffe and TensorFlow. It also supports various networks architectures based on YOLO//
//Thread.sleep(5000);
//Mat image = Imgcodecs.imread("D:\\yolo-object-detection\\yolo-object-detection\\images\\soccer.jpg");
Size sz = new Size(288, 288);
List<Mat> result = new ArrayList<>();
List<String> outBlobNames = getOutputNames(net);
while (true) {
if (cap.read(frame)) {
Mat blob = Dnn.blobFromImage(frame, 0.00392, sz, new Scalar(0), true, false); // We feed one frame of video into the network at a time, we have to convert the image to a blob. A blob is a pre-processed image that serves as the input.//
net.setInput(blob);
net.forward(result, outBlobNames); //Feed forward the model to get output //
// outBlobNames.forEach(System.out::println);
// result.forEach(System.out::println);
float confThreshold = 0.6f; //Insert thresholding beyond which the model will detect objects//
List<Integer> clsIds = new ArrayList<>();
List<Float> confs = new ArrayList<>();
List<Rect> rects = new ArrayList<>();
for (int i = 0; i < result.size(); ++i) {
// each row is a candidate detection, the 1st 4 numbers are
// [center_x, center_y, width, height], followed by (N-4) class probabilities
Mat level = result.get(i);
for (int j = 0; j < level.rows(); ++j) {
Mat row = level.row(j);
Mat scores = row.colRange(5, level.cols());
Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
float confidence = (float) mm.maxVal;
Point classIdPoint = mm.maxLoc;
if (confidence > confThreshold) {
int centerX = (int) (row.get(0, 0)[0] * frame.cols()); //scaling for drawing the bounding boxes//
int centerY = (int) (row.get(0, 1)[0] * frame.rows());
int width = (int) (row.get(0, 2)[0] * frame.cols());
int height = (int) (row.get(0, 3)[0] * frame.rows());
int left = centerX - width / 2;
int top = centerY - height / 2;
clsIds.add((int) classIdPoint.x);
confs.add((float) confidence);
rects.add(new Rect(left, top, width, height));
}
}
}
float nmsThresh = 0.5f;
MatOfFloat confidences = new MatOfFloat(Converters.vector_float_to_Mat(confs));
Rect[] boxesArray = rects.toArray(new Rect[0]);
MatOfRect boxes = new MatOfRect(boxesArray);
MatOfInt indices = new MatOfInt();
Dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThresh, indices); //We draw the bounding boxes for objects here//
int[] ind = indices.toArray();
int j = 0;
for (int i = 0; i < ind.length; ++i) {
int idx = ind[i];
Rect box = boxesArray[idx];
Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(0, 0, 255), 2);
//i=j;
System.out.println(idx);
}
// Imgcodecs.imwrite("D://out.png", image);
//System.out.println("Image Loaded");
ImageIcon image = new ImageIcon(Mat2bufferedImage(frame)); //setting the results into a frame and initializing it //
vidpanel.setIcon(image);
vidpanel.repaint();
System.out.println(j);
System.out.println("Done");
}
}
}
private static BufferedImage Mat2bufferedImage(Mat image) { // The class described here takes in matrix and renders the video to the frame //
MatOfByte bytemat = new MatOfByte();
Imgcodecs.imencode(".jpg", image, bytemat);
byte[] bytes = bytemat.toArray();
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage img = null;
try {
img = ImageIO.read(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return img;
}
}

gray-scale image to matrix and matrix to gray-scale image

I am trying to get 2D matrix from gray-scale image and modify it, then return back to the gray-scale image.
But when try to convert the image to a matrix, the pixels return with black values.
How can I find a solution for this problem?
You can find the images below the code
Java code:
public class MyImageProcessing {
private SampleModel sampleModel;
public int[][] compute(File file)
{
try
{
BufferedImage img= ImageIO.read(file);
Raster raster=img.getData();
sampleModel = raster.getSampleModel();
int w=raster.getWidth(),h=raster.getHeight();
int pixels[][]=new int[w][h];
for (int x=0;x<w;x++)
{
for(int y=0;y<h;y++)
{
pixels[x][y]=raster.getSample(x,y,0);
}
}
return pixels;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public void getImage(int pixels[][])
{
int w=pixels.length;
int h=pixels[0].length;
WritableRaster raster= Raster.createWritableRaster(sampleModel, new Point(0,0));
for(int i=0;i<w;i++)
{
for(int j=0;j<h;j++)
{
raster.setSample(i,j,0,pixels[i][j]);
}
}
BufferedImage image=new BufferedImage(w,h,BufferedImage.TYPE_BYTE_GRAY);
image.setData(raster);
File output=new File("C:\\Users\\salam\\Pictures\\3.png");
try {
ImageIO.write(image,"png",output);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Original image:
Image retrieved from matrix:
Try this code out.
If it is not what you need then perhaps what you could take away from my post is that code should always be neat, readable, properly indented, and commented, all of which adds to the understandability of the program.
Note: Your image returns practically the same black and white image when converted to grayscale, because your image is black and white much like a binary image.
I can also suggest OpenCV (https://opencv.org/) which is under a BSD licence, it's simple, powerful, and available for Java - although I remember it being a PITA when installing it on Ubuntu 16.04.
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
/**
* This class converts images to grayscale color.
*/
public class GrayscaleConverter {
/**
* Creates a new grayscaled BufferedImage object from the given source image
* by averaging each pixels RGB value.
*
* #param inputImageAbsPath the absolute path of the image file, including its name and extension.
* #return a BufferedImage object.
*/
private BufferedImage compute(String inputImageAbsPath) {
System.out.println("... Converting source image to gray scale.");
BufferedImage img = null; // image file
// Read the source image or throw an exception
try {
img = ImageIO.read(new File(inputImageAbsPath));
} catch(Exception e) {
e.printStackTrace();
}
// Get the image width and height dimensions
int width = img.getWidth();
int height = img.getHeight();
// Convert to grayscale by looping over pixels, beginning at top-most left coordinate (0,0)
for (int y = 0; y < height; y++) { // y = rows
for (int x = 0; x < width; x++) { // x = columns
// Get the pixel value at this (x,y) coordinate
int p = img.getRGB(x,y);
// Extract the alpha, R, G, B values from pixel p
int a = (p>>24) & 0xff; // Shift bits and unsign
int r = (p>>16) & 0xff;
int g = (p>>8) & 0xff;
int b = p & 0xff;
// Calculate average color (grayscale it)
int avg = (r+g+b)/3;
// Replace RGB value with avg
p = (a<<24) | (avg<<16) | (avg<<8) | avg;
img.setRGB(x, y, p);
}
}
return img;
}
/**
* Saves the converted grayscale image. This method builds the save path from the provided file name,
* file extension, and absolute path of the folder that you want to save the image in.
*
* #param path the absolute path of the folder that you would like to save the image inside.
* #param imageName the name you would like to save the image with.
* #param imageFileType the image file extension, without the dot (.) preceding the image file type.
* #param image the BufferedImage object returned from the compute method.
*/
private void saveImage(String path, String imageName, String imageFileType, BufferedImage image) {
// Save or throw exception
try {
System.out.println("... Saving grayscale image to "
+ path.concat("\\").concat(imageName).concat(".").concat(imageFileType)); // save path displayed to user
ImageIO.write(image,
imageFileType,
new File(path.concat("\\").concat(imageName).concat(".").concat(imageFileType)));
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("... Image saved.");
}
// Driver
public static void main(String args[]) throws IOException {
/*
* Tested for .png and .jpg files. Both worked successfully.
*/
// Test
System.out.println("Testing GrayscaleConverter.\n");
String input = "*source images absolute file path including name and extension*";
String outputPath = "*absolute path to folder where you will save grayscale image in*";
String outputFileName = "*save image with this name*";
String outputFileType = "*save image with this file extension (no dot (.) e.g. png or jpg)*";
GrayscaleConverter gsc = new GrayscaleConverter();
BufferedImage convertedImage = gsc.compute(input);
gsc.saveImage(outputPath, outputFileName, outputFileType, convertedImage );
System.out.println("\nTest complete.");
}
}
Your supplied input image:
Your output image:
Another sample input image:
Another sample output image:
I tested my program with both .png and .jpg image files and it worked. Good luck.

Negative X or Y obtained from PdfBox while extracting text position

I am trying to extract all text in a pdf along with their coordinates.
I am using Apache PDFBox 2.0.8 and following the sample program DrawPrintTextLocations .
It seems to work mostly, but for certain pdf-s i get negative values for the x and y coordinates of the bounding boxes. Refer this pdf file for example.
My app assumes the coordinate system as a normal pdf (x goes from left to right an y goes top to bottom). so these are throwing my computations off.
Below is the relevant piece of code.
import org.apache.fontbox.util.BoundingBox;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType3Font;
import org.apache.pdfbox.pdmodel.interactive.pagenavigation.PDThreadBead;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
/**
* This is an example on how to get some x/y coordinates of text and to show them in a rendered
* image.
*
* #author Ben Litchfield
* #author Tilman Hausherr
*/
public class DrawPrintTextLocations extends PDFTextStripper {
private AffineTransform flipAT;
private AffineTransform rotateAT;
private AffineTransform transAT;
private final float DPI = 200.0f;
private final double PT2PX = DPI / 72.0;
private final AffineTransform dpiAT = AffineTransform.getScaleInstance(PT2PX, PT2PX);
private final String filename;
static final int SCALE = 1;
private Graphics2D g2d;
private final PDDocument document;
/**
* Instantiate a new PDFTextStripper object.
*
* #param document
* #param filename
* #throws IOException If there is an error loading the properties.
*/
public DrawPrintTextLocations(PDDocument document, String filename) throws IOException {
this.document = document;
this.filename = filename;
}
/**
* This will print the documents data.
*
* #param args The command line arguments.
* #throws IOException If there is an error parsing the document.
*/
public static void main(String[] args) throws IOException {
String pdfLoc = "/debug/pdfbox/p2_VS008PI.pdf";
if (args.length == 1) {
pdfLoc = args[0];
}
try (PDDocument document = PDDocument.load(new File(pdfLoc))) {
DrawPrintTextLocations stripper = new DrawPrintTextLocations(document, pdfLoc);
stripper.setSortByPosition(true);
for (int page = 0; page < document.getNumberOfPages(); ++page) {
stripper.stripPage(page);
}
}
}
private void stripPage(int page) throws IOException {
PDFRenderer pdfRenderer = new PDFRenderer(document);
BufferedImage image = pdfRenderer.renderImageWithDPI(page, DPI);
PDPage pdPage = document.getPage(page);
PDRectangle cropBox = pdPage.getCropBox();
// flip y-axis
flipAT = new AffineTransform();
flipAT.translate(0, pdPage.getBBox().getHeight());
flipAT.scale(1, -1);
// page may be rotated
rotateAT = new AffineTransform();
int rotation = pdPage.getRotation();
if (rotation != 0) {
PDRectangle mediaBox = pdPage.getMediaBox();
switch (rotation) {
case 90:
rotateAT.translate(mediaBox.getHeight(), 0);
break;
case 270:
rotateAT.translate(0, mediaBox.getWidth());
break;
case 180:
rotateAT.translate(mediaBox.getWidth(), mediaBox.getHeight());
break;
default:
break;
}
rotateAT.rotate(Math.toRadians(rotation));
}
// cropbox
transAT = AffineTransform.getTranslateInstance(-cropBox.getLowerLeftX(), cropBox.getLowerLeftY());
g2d = image.createGraphics();
g2d.setStroke(new BasicStroke(0.1f));
g2d.scale(SCALE, SCALE);
setStartPage(page + 1);
setEndPage(page + 1);
Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
writeText(document, dummy);
g2d.dispose();
String imageFilename = filename;
int pt = imageFilename.lastIndexOf('.');
imageFilename = imageFilename.substring(0, pt) + "-marked-" + (page + 1) + ".png";
ImageIO.write(image, "png", new File(imageFilename));
}
/**
* Override the default functionality of PDFTextStripper.
*/
#Override
protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
for (TextPosition text : textPositions) {
AffineTransform at = text.getTextMatrix().createAffineTransform();
PDFont font = text.getFont();
BoundingBox bbox = font.getBoundingBox();
float xadvance = font.getWidth(text.getCharacterCodes()[0]); // todo: should iterate all chars
Rectangle2D.Float rect1 = new Rectangle2D.Float(0, bbox.getLowerLeftY(), xadvance, bbox.getHeight());
if (font instanceof PDType3Font) {
at.concatenate(font.getFontMatrix().createAffineTransform());
} else {
at.scale(1 / 1000f, 1 / 1000f);
}
Shape s1 = at.createTransformedShape(rect1);
s1 = flipAT.createTransformedShape(s1);
s1 = rotateAT.createTransformedShape(s1);
s1 = dpiAT.createTransformedShape(s1);
g2d.setColor(Color.blue);
g2d.draw(s1);
Rectangle bounds = s1.getBounds();
if (bounds.getX() < 0 || bounds.getY() < 0) {
// THIS is where things go wrong
// i need these coordinates to be +ve
System.out.println(bounds.toString());
System.out.println(rect1.toString());
}
}
}
}
And here is some snippet of the output from the first page of the above pdf.
SECTION 10 – INSURANCE & OTHER FINANCIAL RESOURCES
java.awt.Rectangle[x=-3237,y=40,width=19,height=43]
java.awt.Rectangle[x=-3216,y=40,width=20,height=43]
java.awt.Rectangle[x=-3194,y=40,width=23,height=43]
java.awt.Rectangle[x=-3170,y=40,width=22,height=43]
The characters with negative coordinates are outside the cropbox (also characters with coordinates bigger than the cropbox height / width). See the cropbox as a cutout from something bigger. To see the whole thing, run this code
pdPage.setCropBox(pdPage.getMediaBox());
for each page of your PDF and then save and view it.
Per your comment
Following your advice of setting the crop box to the media box, actually changed the whole on screen appearance of the pdf, now i got 3 pages collated as one.
This suggests that physically, this is a folded sheet that has 3 pages on each side. The online PDF displays this as 6 pages for easy viewing on a computer.

java setting resolution and print size for an Image

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.

Categories