My batch jpg resizer works with color images, but grayscale gets blurry

I am having a problem with my Java program. This is for resizing images. You drop it into a folder and run it, and it creates a new folder with the modified images. It works great in color, but it has a problem with shades of gray. Images are transformed, but they become lighter and more blurry, as if someone had ruined the curves or levels. All input files and output files are sRGB color space jpegs saved in RGB color mode. I have thousands of 50 megapixel movies that I'm trying to convert to 15 megapixels or less. Any help or ideas that could be offered would be most valuable. Below is the complete program code, about 130 lines. I have a feeling that the problem may be in the toBufferedImage function, but I lost what might 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 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")); } } 
+1
source share
2 answers

If the jdk classes and methods do not work, report an error for the oracle (oh, I would like to say SUN ..).

And, while the next release will fix the error;), try some work, scaling the image yourself, as suggested here .

Regards, Stefan

+1
source

In your code, you assume jpeg is RGB encoded, but this is not always the case. It is also possible to encode an 8-bit gray scaled jpeg. Therefore, I suggest you try this when creating a BufferedImage, replace:

 BufferedImage.TYPE_INT_RGB; 

 BufferedImage.TYPE_BYTE_GRAY; 

and see if this works for these images.

If so, then you still need to figure out a way to determine the encoding type to automatically change the type of encoding of the BufferedImage color, but you will be closer to the end.

Regards, Stรฉphane

+1
source

Source: https://habr.com/ru/post/1387235/


All Articles