在 Java 中提高图像的分辨率和减小图像的大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13977858/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 14:37:08  来源:igfitidea点击:

Increasing Resolution and Reducing Size of an Image in Java

javagraphicsresolution

提问by Tango

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.

我正在处理从另一个程序返回给我的图像。例如,我可以在 72 DPI 下获得 8x10 的图像,或者在 16x20 下获得相同的图像,同样在 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.

我在 Java 工作。我想做的是获取 16x20 图像并调整其大小。如果可能,我只想更改文件,而不是 72DPI 时的 16x20,而是 144DPI 时的 8x10。

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.

我知道它仍然是相同数量的像素,但观众会说图像有多大以及 DPI 是多少,还有一些人会以全尺寸打开图像,所以我宁愿他们将 16x20 视为较小的图像更高的分辨率。

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?

我可以在 Java 中做到这一点吗?我会丢失任何数据吗?我该怎么做 - 我可以只更改 png 或 jpg 文件中的元数据吗?

-----(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 resolutionwith an image in Java (also here). Any searches I've done have been concerned with decreasing the resolution of an image.

我知道您可以使用 Java 中的图像降低图像分辨率也在这里)。我所做的任何搜索都与降低图像分辨率有关。

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.

我有相反的问题。我正在处理以 72DPI 恢复的图像。优点是我可以增加图片的大小,所以我可以把大小设置为100%、200%、400%等等。所有图像都是 72DPI,所以如果我使用 200% 进行缩放,然后在查看器中打开图像并使其与 100% 图像大小相同,我会看到更好的分辨率。

For clarity - I am getting an image from someone else, it could be generate from a PDF or picture, but I am giventhe 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.

为清楚起见 - 我从其他人那里获取图像,它可以从 PDF 或图片生成,但我从另一个程序获得了图像。不管我做什么,这张图片都是 72DPI。我无法改变它,但我可以将大小指定为 200%,它仍然以 72DPI 返回,只是两倍大并且具有更多细节。

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

我不是图形专家,这是我第一次完成任何使用图形的编程。输出可以是 jpg 或 png,所以格式不是那么重要。(如果需要,我可能也可以使用其他格式。)

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.

假设原始图像是一张照片 - 8" x 10",72 DPI。如果我要求 200% 缩放,我会得到 72DPI 的 16" x 20" 图像。

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?

我可以在 Java 中将较大的 16" x 20" 72DPI 图像更改为 8" x 10" 的 144DPI 图像而不会丢失数据吗?换句话说,将 DPI 加倍,但将大小减半?

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

而且,最重要的是,我可以在不失去分辨率的情况下做到这一点吗?(我认为可以做到。)

采纳答案by Tango

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.

这很棘手,因为就像在 Java 中一样,您不能仅以简单的方式访问某些内容。Java 不跟踪 DPI,但它确实使用每毫米点数。此外,另一个令人困惑的部分是您无法更改图像或 BufferedImage 中的此类信息。您只能在通过 ImageWriter 写出 BufferedImage 时更改此信息。

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.

我能够做到这一点。正如我所说,我可以指定返回给我的图像的缩放比例。无论缩放级别如何,输出都是 72 DPI。我的目标是 300DPI。我指定了 400% 的缩放级别。因此,在 72 DPI 的 8" 宽图像上,返回给我的是 72 DPI 的 32" 图像。我所要做的就是指定 288 (72 x 4) 的 DPI 来覆盖我正在处理的默认 72 DPI,然后当它被写出时,图像具有相同数量的像素,但被认为是在288 DPI 而不是 72 DPI。

Here's a code snippet:

这是一个代码片段:

//Assumed there's already an ImageWriter iw

//假设已经有一个 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

// 从这里开始,只需使用 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();
}

回答by Jim Garrison

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.

不,如果您拍摄 8x10 72dpi 图像并要求 200% 缩放,您将获得 36 dpi 的 16x20。你不能神奇地提高图像分辨率。

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.

重要的是图像中的像素总数。规定的 DPI 正是特定尺寸下的 DPI。以 72dpi 拍摄 8x10 图像。它有 576x720 像素。如果放大到 200%,您仍然拥有相同数量的像素,但现在它们将分布在线性尺寸的两倍上,这意味着单个像素会更大。一些软件将尝试通过内插像素来提高分辨率,即通过平均最近的邻居来创建新像素。这可以给人更高分辨率的印象,但图像不包含更多数据。它始终具有柔化图像的效果,尤其是任何锐利的边缘或线条。

If you reducethe 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.

如果在不重新采样的情况下减小图像的大小,确实会增加打印或显示的分辨率,但图像会变小。对于相同的图像,将 DPI 增加到 144 会将图像大小减小到 4x5。