Search code examples
javaocrtesseractbufferedimagedpi

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);
}

Solution

  • 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.