[英]Why is the color of my image changed after writing it as a jpg file?
I'm currently making a method that converts a ppm file to a jpg, png, and bmp file.我目前正在制作一种将 ppm 文件转换为 jpg、png 和 bmp 文件的方法。 The way I did it is reading the content of a ppm file, creating a BufferedImage, and assigning each pixel from the ppm file to the corresponding pixel in the BufferedImage.我这样做的方法是读取 ppm 文件的内容,创建 BufferedImage,并将 ppm 文件中的每个像素分配给 BufferedImage 中的相应像素。 My bmp and png files look correct.我的 bmp 和 png 文件看起来正确。 However, the jpg file looks completely different.但是,jpg 文件看起来完全不同。
Below is my code:下面是我的代码:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.imageio.ImageIO;
public class readPPMOutputOthers {
public static void main(String[] args) throws InterruptedException {
// read a ppm file
Scanner sc;
// if the file is not found, it will throw an exception
try {
sc = new Scanner(new FileInputStream("res/test2.ppm"));
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("File not found!");
}
// the file now is a StringBuilder
// read line by line to get information
StringBuilder builder = new StringBuilder();
while (sc.hasNextLine()) {
String s = sc.nextLine();
// ignore comment #
if (s.charAt(0) != '#') {
builder.append(s).append(System.lineSeparator());
}
}
sc = new Scanner(builder.toString());
String token;
token = sc.next();
// set the fields
// initial load image
int width = sc.nextInt();
int height = sc.nextInt();
int maxValue = sc.nextInt();
List<Integer> pixels = new ArrayList<>();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int r = sc.nextInt();
int g = sc.nextInt();
int b = sc.nextInt();
int rgb = r;
rgb = (rgb << 8) + g;
rgb = (rgb << 8) + b;
pixels.add(rgb);
}
}
// make a BufferedImage from pixels
BufferedImage outputImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] outputImagePixelData = ((DataBufferInt) outputImg.getRaster().getDataBuffer()).getData();
for (int i = 0; i < pixels.size(); i++) {
outputImagePixelData[i] = pixels.get(i);
}
try {
ImageIO.write(outputImg, "png",
new File("res/test.png"));
ImageIO.write(outputImg, "jpg",
new File("res/test2.jpg"));
ImageIO.write(outputImg, "bmp",
new File("res/test.bmp"));
} catch (IOException e) {
System.out.println("Exception occurred :" + e.getMessage());
}
System.out.println("Images were written successfully.");
}
}
The weird thing is it works for a very large image but not for this small image.奇怪的是它适用于非常大的图像,但不适用于这个小图像。 I need to make it work for such small images because of testing.由于测试,我需要使它适用于如此小的图像。 I've been digging posts about this on google and still didn't find a way to solve this.我一直在谷歌上挖掘关于这个的帖子,但仍然没有找到解决这个问题的方法。 Any help would be appreciated!任何帮助,将不胜感激!
The reason for the strange colors is YUV420 chroma subsumpling used by JPEG encoding.奇怪颜色的原因是 JPEG 编码使用的YUV420色度子采样。
In YUV420 every 2x2 pixels have the same chroma information (the 2x2 pixels have the same color).在 YUV420 中,每 2x2 像素具有相同的色度信息(2x2 像素具有相同的颜色)。
The 2x2 pixels have the same color, but each pixel has different luminance (brighness). 2x2 像素具有相同的颜色,但每个像素具有不同的亮度(亮度)。
The YUV420 Chroma subsumpling is demonstrated in Wikipedia : Wikipedia中演示了 YUV420 Chroma subsumpling:
And in our case:在我们的例子中:
becomes变成
The brown color is a mixture of the original red, cyan magenta and the yellow colors (the brown color is "shared" by the 4 pixels).棕色是原始红色、青色洋红色和黄色的混合(棕色由 4 个像素“共享”)。
The commonly used JPEG color format is YUV420, but JPEG standard does support YUV444 Chroma subsumpling.常用的 JPEG 颜色格式是 YUV420,但 JPEG 标准确实支持 YUV444 Chroma subsumpling。
GIMP manages to save JPEG images with YUV444 Chroma subsumpling. GIMP设法使用 YUV444 Chroma subsumpling 保存 JPEG 图像。
Example (2x2 image):示例(2x2 图像):
Too small:太小: Enlarged:放大:
I couldn't find an example for saving YUV444 JPEG in JAVA...我找不到在 JAVA 中保存 YUV444 JPEG 的示例...
To some degree the effect you describe is to be expected.在某种程度上,您描述的效果是可以预期的。
From https://en.wikipedia.org/wiki/JPEG :来自https://en.wikipedia.org/wiki/JPEG :
JPEG is a commonly used method of lossy compression for digital images, particularly for those images produced by digital photography. JPEG 是一种常用的数字图像有损压缩方法,特别是对于那些由数字摄影产生的图像。 The degree of compression can be adjusted, allowing a selectable tradeoff between storage size and image quality.可以调整压缩程度,允许在存储大小和图像质量之间进行可选择的权衡。 JPEG typically achieves 10:1 compression with little perceptible loss in image quality. JPEG 通常实现 10:1 压缩,图像质量几乎没有可察觉的损失。
Maybe when storing small files you can set the compression to be low and thus increase quality.也许在存储小文件时,您可以将压缩设置为低,从而提高质量。 See Setting jpg compression level with ImageIO in Java请参阅在 Java 中使用 ImageIO 设置 jpg 压缩级别
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.