Increasing Resolution and Reducing Size of an Image in Java

11,578

Solution 1

This is tricky because, like so much in Java, you can't just access something in a simple way. Java does not keep track of DPI, but it does use dots per millimeter. Also, another part that is confusing is that you cannot change this kind of information in an image, or in a BufferedImage. You can only change this information when you are writing a BufferedImage out through an ImageWriter.

I was able to do this. As I said, I could specify the zoom on the image that was returned to me. No matter what zoom level, the output was 72 DPI. My goal was 300DPI. I specified a zoom level of 400%. So, on an 8" wide image of 72 DPI, that returned to me a 32" image of 72 DPI. All I had to do was specify a DPI of 288 (72 x 4) to override the default 72 DPI I was dealing with and then when it was written out, the image had the same number of pixels, but was considered to be done at 288 DPI rather than 72 DPI.

Here's a code snippet:

//Assumed there's already an ImageWriter iw

ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier =
       ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
    continue;
}

// Set Parameters and info

int DPI = 72 * scaling/100;
double dotsPerMilli = 1.0 * DPI / 10 / 2.54;
double checkDots = 1.0 * 144 / 10 / 2.54;
System.out.println("Dots per inch: " + DPI + ", DotsPerMilli: " + dotsPerMilli + ",
    CheckDots = " + checkDots);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);

// From here, just write out file using an ImageOutputStream

final ImageOutputStream stream = ImageIO.createImageOutputStream(outFile);
System.out.println("Output file: " + outFile);
try {
    writer.setOutput(ImageIO.createImageOutputStream(outFile));
    writer.write(metadata, new IIOImage(image_to_save, null, metadata),
    writeParam);
} catch (Exception e) {
    System.out.println("Caught exception " + e + " when trying to write out
        file.");
    System.exit(0);
} finally {
    stream.close();
}

Solution 2

No, if you take an 8x10 72dpi image and ask for a 200% zoom you'll get a 16x20 at 36 dpi. You can't magically increase image resolution.

What counts is the total number of pixels in the image. The stated DPI is just what the DPI will be at a specific size. Take your 8x10 image at 72dpi. It has 576x720 pixels. If you zoom to 200% you still have the same number of pixels, but now they'll be spread out over twice the linear dimensions, meaning the individual pixels will be bigger. Some software will attempt to increase resolution by interpolating pixels, i.e. creating new pixels by averaging the nearest neighbors. This can give the impression of higher resolution but the image does not contain any more data. It always has the effect of softening the image, especially any sharp edges or lines.

If you reduce the size of an image without resampling, you do increase the printed or displayed resolution, but the image gets smaller. For the same image, increasing the DPI to 144 will reduce the image size to 4x5.

Share:
11,578
Tango
Author by

Tango

I'm working on creating my own film production company, but the problem is that interferes too much with another passion: ballroom dancing. (I just love a good tango!) I'm a writer, but also have done programming and other types of work.

Updated on June 04, 2022

Comments

  • Tango
    Tango almost 2 years

    When I first asked this, I included as much information as I could, since I never know what will help someone if they can give m a solution, but from the answers, it seems I didn't make my point clear.

    I'm leaving the original text at the bottom and shortening this. I hope that makes it clear.

    I am working with images returned to me from another program. I can get an image that's, for example, 8x10 at 72 DPI or the same image at 16x20, also at 72DPI.

    I'm working in Java. What I'd like to do is take the 16x20 image and resize it. If possible, I'd like to just change the file so instead of being 16x20 at 72DPI, it's 8x10 at 144DPI.

    I know that it's still the same number of pixels, but viewers will say how big an image is and what the DPI is and also some open an image to its full size, so I'd rather them treat the 16x20 as a smaller image with a higher resolution.

    Can I do that in Java? Will I lose any data? How would I do it - can I just change the metadata in the png or jpg file?

    -----(original question below here)-----

    I've seen a few questions that come close to this, but this is a little different.

    I know you can decrease image resolution with an image in Java (also here). Any searches I've done have been concerned with decreasing the resolution of an image.

    I have the opposite problem. I'm working with an image that I'm getting back in 72DPI. The advantage is I can increase the size of the picture, so I could make the size 100%, 200%, 400% and so on. All images are at 72DPI, so if I use 200% for the zoom, then open the image in a viewer and make it the same size as the 100% image, I am seeing a better resolution.

    For clarity - I am getting an image from someone else, it could be generate from a PDF or picture, but I am given the image from another program. No matter what I do, this image is at 72DPI. I can't change that, but I can specify the size at 200% and it still comes back at 72DPI, just twice as big and with more detail.

    I'm no graphics expert and this is the first time I've done any programming that uses graphics. The output could be jpg or png, so the format isn't that important. (I could probably also use other formats if needed.)

    Let's say the original image is a photo - 8" x 10", and at 72 DPI. If I ask for a 200% zoom, I get a 16" x 20" image at 72DPI.

    Can I, within Java, change that larger 16" x 20" 72DPI image to a 144DPI image that's 8" x 10" without losing data? In other words, double the DPI, but cut the size in half?

    And, most importantly, can I do it without losing resolution? (I would think that can be done.)