Java - Compressed Image size is bigger than original (BufferedImage) - java

I'm trying to compress an image to upload to S3 Bucket but after the image is compressed, the size of the compressed image is larger than the original. From 227KB -> 236KB
Can anybody explain for me why this happened?
Here's my code:
BufferedImage bufferedImage = ImageIO.read(photoFile);
File compressedImageFile = new File("compressed_image.jpeg");
OutputStream outputStream = new FileOutputStream(compressedImageFile);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
ImageWriter imageWriter = writers.next();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
if (imageWriteParam.canWriteCompressed()) {
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(0.5f);
}
imageWriter.write(null, new IIOImage(bufferedImage, null, null), imageWriteParam);
log.info("Close stream");
outputStream.close();
imageOutputStream.close();
imageWriter.dispose();
Here's my image:
original - 227KB
compressed - 236KB
I tried to change the compression quality but it doesn't seem working, and this problem happens in some case, not all

jpeg images are already compressed. “Compressing” an already compressed file makes it a bit bigger (header data) each time.
A text file on the other hand will get much smaller.

Related

Reduce the filesize of a JPG file in java

We have generated a JPG file by using
org.openqa.selenium.TakesScreenshot class
File src = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
File dest = new File("C:\\Users\\admin\\Desktop\\Images\\29_18-03-20-07-11-47.jpg");
FileHandler.copy(src, dest);
As the generated image is having file size of 1.5MB to 2.9MB size. We want to reduce the file size to kbs.
we tried ImageIO but the generated image is not having original file color space/color profile.
File input = new File("C:\\Users\\admin\\Desktop\\Images\\29_18-03-20-07-11-47.jpg");
File compressedImageFile = new File("C:\\Users\\admin\\Desktop\\Images\\compressed_image7.jpg");
BufferedImage image = ImageIO.read(input);
OutputStream os = new FileOutputStream(compressedImageFile);
Iterator<ImageWriter writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.05f);
writer.write(null, new IIOImage(image, null, null), param);
Could not share the image or screen shot
Could someone let me know how can I reduce the filesize
Try using lossless JPEG
ImageWriter writer= (ImageWriter) ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param= writer.getDefaultWriteParam();
param.setCompressionMode(param.MODE_EXPLICIT);
param.setCompressionType("JPEG-LS");
writer.setOutput(ImageIO.createImageOutputStream(new File(path)));
writer.write(null, new IIOImage(image, null, null), param);

How to keep compressing a image with ImageWriter in JAVA?

I need to compress every image that is larger than 500 kbytes.
So, i'm trying to create a code that will test every compression quality until i get <= 500 kb, then i'll have the best quality with the lowest length.
My biggest problem here is that writer method from ImageWriter appends my new image to the old. So, if i have a 600kb image and write a new one with low quality, i'll have 600kb + probably 500kb (size of the new image) in the same .jpg file and with a low quality.
My code:
public byte[] imageCompressor(String filePath, String newFileName, String formatName) throws IOException {
File input = new File(filePath);
BufferedImage image = ImageIO.read(input);
File compressedImageFile = new File(newFileName);
String compressedWithFormat = compressedImageFile + "." + formatName;
OutputStream os = new FileOutputStream(compressedWithFormat);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
ImageWriter writer = (ImageWriter) writers.next();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ImageIO.createImageOutputStream(baos));
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
writer.write(null, new IIOImage(image, null, null), param);
float contador = 1f;
while (imageSizeChecker(compressedWithFormat) > 500) {
param.setCompressionQuality(contador -= 0.09f); // Change the quality value you prefer
writer.write(null, new IIOImage(image, null, null), param);
System.out.println(imageSizeChecker(compressedWithFormat));
writer.dispose();
}
writer.dispose();
return baos.toByteArray();
}
public Long imageSizeChecker(String filePath) {
File insertFile = new File(filePath);
Long fileSize = insertFile.length() / 1024;
return fileSize;
}
Also, i want to return the image in a byte array (as it follows), and i'm trying to send the image file on the parameter as a byte array (replacing String filepath for byte[] filepath)
You keep writing multiple images to the same ByteArrayOutputStream. To reset the output stream and discard the data between each image, you can use:
baos.reset();
There are several other problems -- such as inspecting a file you never write -- but if you're finding that appended data is the major problem, this seems to be why.

Java Image Compression : colour changes

I am using below code for reducing image size. It reduces size from 1MB to 250 KB. Its fine but it changes image colour.
File input = new File("ImageTOCompress.jpg");
BufferedImage image = ImageIO.read(input);
File compressedImageFile = new File("CompressedImage.jpg");
OutputStream os =new FileOutputStream(compressedImageFile);
Iterator<ImageWriter>writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.05f);
writer.write(null, new IIOImage(image, null, null), param);
os.close();
ios.close();
writer.dispose();
Please help me to maintain image colour as it is...Thanks!!!

How to decompress an image stored using stenography? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am currently doing project related to "image steganography" in Java, for that I want to compress and decompress the secret image. I have done the compression part. But I don't know how to perform the decompression part.
I have compressed the JPEG image using the following code:
public class CompressJPEGFile {
public static void main(String[] args) throws IOException {
File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\d.jpg");
File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compress.jpg");
InputStream is = new FileInputStream(imageFile);
OutputStream os = new FileOutputStream(compressedImageFile);
float quality = 0.5f;
BufferedImage image = ImageIO.read(is);
// get all image writers for JPG format
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
if (!writers.hasNext())
throw new IllegalStateException("No writers found");
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
//associated stream and image metadata and thumbnails to the output
writer.write(null, new IIOImage(image, null, null), param);
// close all streams
is.close();
os.close();
ios.close();
writer.dispose();
}
}
I have written the code for decompression. Is the code right if I am not considering the quality of image?
public static void decompress() throws FileNotFoundException {
try {
File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compressnew.jpg");
File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\dnew.jpg");
InputStream is = new FileInputStream(compressedImageFile);
OutputStream os = new FileOutputStream(imageFile );
BufferedImage image = ImageIO.read(is);
// get all image writers for JPG format
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
if (!writers.hasNext()) {
throw new IllegalStateException("No writers found");
}
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
writer.write(null, new IIOImage(image, null, null), param);
//associated stream and image metadata and thumbnails to the output
is.close();
os.close();
ios.close();
writer.dispose();
} catch (IOException ex) {
Logger.getLogger(CompressJPEGFile.class.getName()).log(Level.SEVERE, null, ex);
}
}
I think you are looking for a lossless a compression scheme that is such that you can retrieve a secret from steganography. That means you need to move away from jpg as your compression format - it is lossy. That means that once you have put your secret + cover image through the jpg compression, the original cannot be recovered by a simple 'decompression' call at the other end, i.e. the JPEG compression algorithm is not reversible.
You ask in comments about libraries for compression / decompression rather than steganography. You are already using one in your code example (ImageIO). If you want to take your original image and transcode it to PNG (i.e. lossless compression), ImageIO can do that simply - see this question for details. JAI is commonly used if you need more advanced features. The PNG format offers a lossless compression option.
EDIT:
some code to show using ImageIO using PNG format as requested by OP in comments. By default ImageIO uses compression when you write PNG's. At the receive end, simply read the PNG, you get the original back.:
public class JPEGFileToPNG {
public static void main(String[] args) throws IOException {
File imageFile = new File("C:\\Users\\user\\Desktop\\encryption\\d.jpg");
File compressedImageFile = new File("C:\\Users\\user\\Desktop\\encryption\\compress.png");
BufferedImage image = ImageIO.read(imageFile.toURI().toURL());
ImageIO.write(image, "png", compressedImageFile);
}
P.S. There are two levels at which to answer your question. At the more advanced (maybe research) level - people do work on using the actual errors introduced by JPG encoding to encode the secret in steganography (e.g. http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=1357167&tag=1) From the wording of your question, I don't think this is what you want, but it might be. In which case, your task is quite hard (writing a JPEG encoder / decoder and adapting it to hide secrets in the encoding table), but it has been done (e.g. this paper describes the method).

png file turn all black when compress to jpeg. Is it because PNG is lossless?

I have a piece of code that compress an jpg image with a certain quality, but when the image is png type, they all turn black. Any idea why and how to fix it? here is my code.
public void compressImage(String filename, ServletContext servletContext) {
//You first need to enumerate the image writers that are available to jpg
Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
//Then, choose the first image writer available
ImageWriter writer = (ImageWriter) iter.next();
//instantiate an ImageWriteParam object with default compression options
ImageWriteParam iwp = writer.getDefaultWriteParam();
//Set the compression quality
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(0.5f);
try {
BufferedImage img = ImageIO.read(new File(filename));
String destPath = "/Users/KingdomHeart/resources/scholar/compress/compress.jpg";
File file = new File(destPath);
FileImageOutputStream output = new FileImageOutputStream(file);
writer.setOutput(output);
IIOImage image = new IIOImage(img, null, null);
writer.write(null, image, iwp);
writer.dispose();
}catch(IOException e){
}
}
This might have the answers you're looking for: Converting transparent gif / png to jpeg using java
The issue is likely that you're working with a PNG that has some transparency in it.

Categories

Resources