PNG 到 JPG 的转换问题

PNG to JPEC conversion issues

我有这个 png 文件并将其转换为 jpg 图片。

如您所见,圆圈周围的一些像素不如 png 图像中的圆圈光滑。

我有这段代码可以将 png 转换为 jpeg。如何更新代码,以便去除圆圈周围的噪音。

BufferedImage bufferedJpgImage = new BufferedImage(inputPngImage.getWidth(null),
                                                inputPngImage.getHeight(null),
                                                BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(inputPngImage, 0, 0, bufferedJpgImage.getWidth(), bufferedJpgImage.getHeight(), Color.WHITE, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedJpgImage, "jpg", out);

Jpeg 使用有损压缩算法,这意味着修改物理图像数据以减小图像大小。

您可以通过ImageIO设置压缩级别,有点乱,但应该可以提供您需要的控制。

因此,根据 Setting jpg compression level with ImageIO in Java 的答案,您可以这样做:

左边是原图BufferedImage,右边是生成的 JPEG

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) {
        try {
            BufferedImage original = ImageIO.read(...);
            BufferedImage bufferedJpgImage = new BufferedImage(original.getWidth(null),
                            original.getHeight(null),
                            BufferedImage.TYPE_INT_RGB);
            Graphics2D g = bufferedJpgImage.createGraphics();
            g.drawImage(original, 0, 0, original.getWidth(), original.getHeight(), Color.WHITE, null);
            g.dispose();

            File jpg = new File("tmp.jpg");

            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

                write(bufferedJpgImage, baos);

                try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) {

                    BufferedImage image = ImageIO.read(bais);

                    JPanel panel = new JPanel();
                    panel.add(new JLabel(new ImageIcon(original)));
                    panel.add(new JLabel(new ImageIcon(image)));

                    JOptionPane.showMessageDialog(null, panel);

                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void write(BufferedImage capture, OutputStream to) throws IOException {
// use IIORegistry to get the available services
        IIORegistry registry = IIORegistry.getDefaultInstance();
// return an iterator for the available ImageWriterSpi for jpeg images
        Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class,
                        new ServiceRegistry.Filter() {
                            @Override
                            public boolean filter(Object provider) {
                                if (!(provider instanceof ImageWriterSpi)) {
                                    return false;
                                }

                                ImageWriterSpi writerSPI = (ImageWriterSpi) provider;
                                String[] formatNames = writerSPI.getFormatNames();
                                for (int i = 0; i < formatNames.length; i++) {
                                    if (formatNames[i].equalsIgnoreCase("JPEG")) {
                                        return true;
                                    }
                                }

                                return false;
                            }
                        },
                        true);
//...assuming that servies.hasNext() == true, I get the first available service.
        ImageWriterSpi writerSpi = services.next();
        ImageWriter writer = writerSpi.createWriterInstance();

// specifies where the jpg image has to be written      
        writer.setOutput(ImageIO.createImageOutputStream(to));

        JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
        jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        jpegParams.setCompressionQuality(1f);

// writes the file with given compression level 
// from your JPEGImageWriteParam instance
        writer.write(null, new IIOImage(capture, null, null), jpegParams);
    }

}

您需要确保正确管理您的资源,在使用完后关闭或处置它们

您看到的是非照片图像中 JPEG 压缩的自然结果。 JPEG 依赖于人们无法注意到摄影图像中的小刻度。当从一种颜色突然变为另一种颜色时,您会看到伪影。

您可以通过量化 table 选择(大多数编码器中的质量设置)并且不以低于 Y 的速率对 Cb 和 Cr 分量进行采样来减少这种影响。

但是,对于您所展示的图像,您最好坚持使用 PNG。