我的批量 jpg 缩放器适用于彩色图像,但灰度图像会被冲掉

发布于 2024-11-17 08:39:50 字数 4759 浏览 3 评论 0原文

我的 Java 程序遇到了问题。它用于调整图像大小。您将其放入文件夹并运行它,它会创建一个包含调整大小的图像的新文件夹。它在颜色上效果很好,但在灰度上有问题。图像被转换,但它们变得更亮,更褪色,就好像有人弄乱了曲线或水平。所有输入文件和输出文件都是sRGB颜色空间jpeg,以RGB颜色模式保存。我有数千张 50 兆像素的胶片扫描件,我正在尝试将其转换为 15 兆像素或更低。任何人可以提供的任何帮助或想法将不胜感激。程序完整代码如下,大约130行。我有一种感觉问题可能出在 toBufferedImage 函数中,但我不知道它可能是什么。

package jpegresize;

import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;

public class Main {

public static void main(String[] args) {

    System.out.println("JPEGResize running . . .");

    int max_side = 4096;
    float quality = 0.9f;

    if(args.length == 0) System.out.println("No maximum side resolution or compression quality arguments given, using default values.\nUsage: java -jar JPEGResize.jar <maximum side resolution in pixels> <quality 0 to 100 percent>");
    if(args.length >= 1) max_side = Integer.parseInt(args[0]);
    if(args.length >= 2) quality = Float.parseFloat(args[1]) / 100.0f;

    System.out.println("Maximum side resolution: " + max_side);
    System.out.println("Compression quality: " + (quality * 100) + "%");

    File folder = new File(".");
    File[] listOfFiles = folder.listFiles(new JPEGFilter());

    for(int i = 0; i < listOfFiles.length; i++) {

        System.out.println("Processing " + listOfFiles[i].getName() + " . . .");
        resizeFile(listOfFiles[i].getName(), max_side, quality);
        System.out.println("Saved /resized/" + listOfFiles[i].getName());
    }

    System.out.println("Operations complete.");
}

public static void resizeFile(String filename, int max_side, float quality) {

    try
    {
        BufferedImage input_img = ImageIO.read(new File(filename));

        double aspect_ratio = ((double)input_img.getWidth()) / ((double)input_img.getHeight());
        int width, height;

        if(input_img.getWidth() >= input_img.getHeight()) {

            width = max_side;
            height = (int)(((double)max_side) / aspect_ratio);
        }
        else {

            width = (int)(((double)max_side) * aspect_ratio);
            height = max_side;
        }

        Image scaled_img = input_img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage output_img = toBufferedImage(scaled_img);

        Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
        ImageWriter writer = (ImageWriter)iter.next();
        ImageWriteParam iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(quality);

        File doesDirExist = new File("resized/");
        if(!doesDirExist.exists())
            new File("resized").mkdir();

        File file = new File("resized/" + filename);
        FileImageOutputStream output = new FileImageOutputStream(file);
        writer.setOutput(output);
        IIOImage image = new IIOImage(output_img, null, null);
        writer.write(null, image, iwp);
        writer.dispose();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
    if (image instanceof BufferedImage) {
        return (BufferedImage)image;
    }

    // This code ensures that all the pixels in the image are loaded
    image = new ImageIcon(image).getImage();

    // Create a buffered image with a format that's compatible with the screen
    BufferedImage bimage = null;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try {
        // Determine the type of transparency of the new buffered image
        int transparency = Transparency.OPAQUE;

        // Create the buffered image
        GraphicsDevice gs = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        bimage = gc.createCompatibleImage(
            image.getWidth(null), image.getHeight(null), transparency);
    } catch (HeadlessException e) {
        // The system does not have a screen
    }

    if (bimage == null) {
        // Create a buffered image using the default color model
        int type = BufferedImage.TYPE_INT_RGB;
        bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
    }

    // Copy image to buffered image
    Graphics g = bimage.createGraphics();

    // Paint the image onto the buffered image
    g.drawImage(image, 0, 0, null);
    g.dispose();

    return bimage;
}
}

class JPEGFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
    return (name.toLowerCase().endsWith(".jpg")) || (name.toLowerCase().endsWith(".jpeg"));
    }
}

I've been having a problem with my Java program. It's for resizing images. You drop it into a folder and run it, and it creates a new folder with the resized images. It works great on color, but it has a problem with grayscale. The images are converted, but they become lighter and more washed out, as if someone has messed with the curves or levels. All the input files and output files are sRGB color space jpegs, saved in RGB color mode. I have thousands of 50 megapixel film scans I'm trying to convert down to 15 megapixels or less. Any help or ideas anyone could offer would be most appreciated. The programs full code is below, it's about 130 lines. I have a feeling the problem may be in the toBufferedImage function but I'm lost as to what it could be.

package jpegresize;

import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;

public class Main {

public static void main(String[] args) {

    System.out.println("JPEGResize running . . .");

    int max_side = 4096;
    float quality = 0.9f;

    if(args.length == 0) System.out.println("No maximum side resolution or compression quality arguments given, using default values.\nUsage: java -jar JPEGResize.jar <maximum side resolution in pixels> <quality 0 to 100 percent>");
    if(args.length >= 1) max_side = Integer.parseInt(args[0]);
    if(args.length >= 2) quality = Float.parseFloat(args[1]) / 100.0f;

    System.out.println("Maximum side resolution: " + max_side);
    System.out.println("Compression quality: " + (quality * 100) + "%");

    File folder = new File(".");
    File[] listOfFiles = folder.listFiles(new JPEGFilter());

    for(int i = 0; i < listOfFiles.length; i++) {

        System.out.println("Processing " + listOfFiles[i].getName() + " . . .");
        resizeFile(listOfFiles[i].getName(), max_side, quality);
        System.out.println("Saved /resized/" + listOfFiles[i].getName());
    }

    System.out.println("Operations complete.");
}

public static void resizeFile(String filename, int max_side, float quality) {

    try
    {
        BufferedImage input_img = ImageIO.read(new File(filename));

        double aspect_ratio = ((double)input_img.getWidth()) / ((double)input_img.getHeight());
        int width, height;

        if(input_img.getWidth() >= input_img.getHeight()) {

            width = max_side;
            height = (int)(((double)max_side) / aspect_ratio);
        }
        else {

            width = (int)(((double)max_side) * aspect_ratio);
            height = max_side;
        }

        Image scaled_img = input_img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage output_img = toBufferedImage(scaled_img);

        Iterator iter = ImageIO.getImageWritersByFormatName("jpeg");
        ImageWriter writer = (ImageWriter)iter.next();
        ImageWriteParam iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(quality);

        File doesDirExist = new File("resized/");
        if(!doesDirExist.exists())
            new File("resized").mkdir();

        File file = new File("resized/" + filename);
        FileImageOutputStream output = new FileImageOutputStream(file);
        writer.setOutput(output);
        IIOImage image = new IIOImage(output_img, null, null);
        writer.write(null, image, iwp);
        writer.dispose();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
    if (image instanceof BufferedImage) {
        return (BufferedImage)image;
    }

    // This code ensures that all the pixels in the image are loaded
    image = new ImageIcon(image).getImage();

    // Create a buffered image with a format that's compatible with the screen
    BufferedImage bimage = null;
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try {
        // Determine the type of transparency of the new buffered image
        int transparency = Transparency.OPAQUE;

        // Create the buffered image
        GraphicsDevice gs = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        bimage = gc.createCompatibleImage(
            image.getWidth(null), image.getHeight(null), transparency);
    } catch (HeadlessException e) {
        // The system does not have a screen
    }

    if (bimage == null) {
        // Create a buffered image using the default color model
        int type = BufferedImage.TYPE_INT_RGB;
        bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
    }

    // Copy image to buffered image
    Graphics g = bimage.createGraphics();

    // Paint the image onto the buffered image
    g.drawImage(image, 0, 0, null);
    g.dispose();

    return bimage;
}
}

class JPEGFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
    return (name.toLowerCase().endsWith(".jpg")) || (name.toLowerCase().endsWith(".jpeg"));
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北渚 2024-11-24 08:39:50

如果jdk的类和方法有bug,请将bug报告给oracle(哦!我希望我能继续对SUN说..)。

并且,虽然下一个版本将纠正该错误;),但请尝试一些解决方法,自行缩放图像,例如

问候,
史蒂芬

If jdk's classes and methods are buggy, report the bug to oracle (oh! I wish I could go on saying to SUN..).

And, while the next release will correct the bug ;), try some work arounds, scaling image by yourself like proposed here.

Regards,
Stéphane

烟雨扶苏 2024-11-24 08:39:50

在您的代码中,您假设 jpeg 以 RGB 编码,但情况并非总是如此。还可以对 8 位灰度 jpeg 进行编码。因此,我建议您在构建 BufferedImage 时尝试此操作,将 : 替换

BufferedImage.TYPE_INT_RGB;

BufferedImage.TYPE_BYTE_GRAY;

,看看它是否适用于这些图像。

如果是这样,那么您仍然需要找到一种方法来确定编码类型,以自动更改要使用的 BufferedImage 颜色编码类型,但您会更近一步。

问候,
史蒂芬

In your code, you assume jpeg are encoded in RGB, but that's not always the case. It's also possible to encode 8 bit gray scaled jpeg. So I suggest that you try this when building your BufferedImage, replace :

BufferedImage.TYPE_INT_RGB;

by

BufferedImage.TYPE_BYTE_GRAY;

and see if it works for those images.

If so, then you still have to find out a way to determine the encoding type to automatically change the type of BufferedImage color encoding to use, but you will be one stop closer.

Regards,
Stéphane

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文