Мой пакетный jpg resizer работает с цветными изображениями, но оттенки серого становятся размытыми - PullRequest
1 голос
/ 25 июня 2011

У меня проблема с моей программой на Java.Это для изменения размера изображений.Вы помещаете его в папку и запускаете, и он создает новую папку с измененными размерами изображений.Он прекрасно работает с цветом, но у него есть проблемы с оттенками серого.Изображения преобразуются, но они становятся более светлыми и более размытыми, как будто кто-то перепутал кривые или уровни.Все входные и выходные файлы имеют формат sRGB jpegs и сохраняются в цветовом режиме 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"));
    }
}

Ответы [ 2 ]

1 голос
/ 25 июня 2011

Если классы и методы jdk содержат ошибки, сообщите об ошибке оракулу (о! Хотелось бы, чтобы я продолжал говорить СОЛНЦЕ ..).

И, хотя следующий выпуск исправит ошибку;), попробуйте немного обойтись, масштабируя изображение самостоятельно, как , предложенное здесь .

С уважением, Стефан

1 голос
/ 25 июня 2011

В вашем коде вы предполагаете, что jpeg закодированы в RGB, но это не всегда так. Также возможно кодировать 8-битный серый масштабированный JPEG. Поэтому я предлагаю вам попробовать это при создании BufferedImage, заменить:

BufferedImage.TYPE_INT_RGB;

по

BufferedImage.TYPE_BYTE_GRAY;

и посмотрите, работает ли он для этих изображений.

Если это так, то вам все равно нужно найти способ определить тип кодировки для автоматического изменения типа используемой цветовой кодировки BufferedImage, но вы будете на один шаг ближе.

С уважением, Stéphane

...