How to reduce PNG/JPEG file size in spring boot - java

I want to reduce the file size while saving the image.
Please, take this code for reference.
And how to reduce the file size.
public void saveImage(MultipartFile image_one, MultipartFile image_two, MultipartFile image_three) throws Exception{
System.out.println("Inside Save image Repo");
String folder = "C:/Users/HP/Photos";
byte[] bytes_one;
try {
bytes_one = image_one.getBytes();
Path path1 = Paths.get(folder + image_one.getOriginalFilename());
System.out.println("Path of 1st imagae : "+path1);
Files.write(path1, bytes_one);
System.out.println("Image-1 size : "+bytes_one.length);
} catch (Exception e) {
System.out.println("Inside Catch Block -> Image not found ");
e.printStackTrace();
}
}

You could use the Java javax.imageio library and use a function to compress your image bytes.
This should do the work:
public byte[] compressImage(MultipartFile image) throws IOException
{
InputStream inputStream = image.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
float imageQuality = 0.3f;
// Create the buffered image
BufferedImage bufferedImage = ImageIO.read(inputStream);
// Get image writers
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("jpg"); // Input your Format Name here
if (!imageWriters.hasNext())
throw new IllegalStateException("Writers Not Found!!");
ImageWriter imageWriter = imageWriters.next();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
// Set the compress quality metrics
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(imageQuality);
// Compress and insert the image into the byte array.
imageWriter.write(null, new IIOImage(bufferedImage, null, null), imageWriteParam);
byte[] imageBytes = outputStream.toByteArray();
// close all streams
inputStream.close();
outputStream.close();
imageOutputStream.close();
imageWriter.dispose();
return imageBytes;
}
It returns the compressed image bytes so that the value returned can be transformed into a number of things. In your case, in a file...
byte[] compressedImageBytes = compressImage(imageOne);
Files.write(path1, bytesOne);

Related

Image file compression in java

I'm trying to compress an image file(jpg) using ImageIO. my goal is to compress image to 30 kb or less. Below is the code i used to compress image. The code is working fine. But it is not compressing to 30 kb, even if i tried again with the compressed image.
Then I try to scale the image. that time i got 30 kb file but quality is vet\y poor.
My file is an image of an application form. So I need the data to be readable.
Is ther any way i can do this with ImageIO or any other libraries.
public void jpegCompression(File imageFile,String path,Integer flag) {
try {
File compressedImageFile = new File(path+flag+"_"+imageFile.getName());
InputStream is = new FileInputStream(imageFile);
OutputStream os = new FileOutputStream(compressedImageFile);
float quality = 0.1f;
// create a BufferedImage as the result of decoding the supplied InputStream
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();
// compress to a given quality
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
// appends a complete image stream containing a single image and
//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();
} catch (IOException e) {
e.printStackTrace();
}
}

Compressing and converting a jpg to tiff in Java

I have a jpg image and I want to convert it to a tiff file, but when I create the output file from byteArrayOutputStream, the output file has 0 byte length.
public static void main(String[] args) throws Exception {
String root = "E:\\Temp\\imaging\\test\\";
File image = new File(root + "0riginalTif-convertedToJpg.JPG");
byte[] bytes = compressJpgToTiff(image);
File destination = new File(root + "OriginalJpg-compressedToTiff.tiff");
FileOutputStream fileOutputStream = new FileOutputStream(destination);
fileOutputStream.write(bytes);
}
public static byte[] compressJpgToTiff(File imageFile) throws Exception {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(255);
ImageOutputStream imageOutputStream = null;
try {
File input = new File(imageFile.getAbsolutePath());
Iterator<ImageWriter> imageWriterIterator = ImageIO.getImageWritersByFormatName("TIF");
ImageWriter writer = imageWriterIterator.next();
imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream);
writer.setOutput(imageOutputStream);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("JPEG");
param.setCompressionQuality(0.1f);
BufferedImage bufferedImage = ImageIO.read(input);
writer.write(null, new IIOImage(bufferedImage, null, null), param);
writer.dispose();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (imageOutputStream != null)
imageOutputStream.close();
byteArrayOutputStream.close();
}
}
I want to reduce the size of output tiff as much as possible. Is there a better approach? Is it even possible to reduce the size of a tiff image?
return byteArrayOutputStream.toByteArray(); but you didn't wirite data to byteArrayOutputStream. Look, you just added data to writer.
About compression of tiff file, you have already done it with - param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
Your byteArrayOutputStream object is getting closed in finally block before you converting byteArrayOutputStream to byteArray using byteArrayOutputStream.toByteArray() thats why you getting content length to be 0. So modify your code once as below :
public static byte[] compressJpgToTiff(File imageFile) throws Exception {
//Add rest of your method code here
writer.dispose();
byte[] bytesToReturn = byteArrayOutputStream.toByteArray();
return bytesToReturn;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (imageOutputStream != null)
imageOutputStream.close();
byteArrayOutputStream.close();
}
}

How to reduce size of a multipart file in java

I have Java Spring MVC application in which there is an option to upload an image and save to the server. i have the following method:
#RequestMapping(value = "/uploaddocimagecontentsubmit", method = RequestMethod.POST)
public String createUpdateFileImageContentSubmit(#RequestParam("file") MultipartFile file, ModelMap model)
{
//methods to handle file upload
}
I am now trying to reduce the size of the image refering the following:
increasing-resolution-and-reducing-size-of-an-image-in-java and decrease-image-resolution-in-java
The problem I am facing is that in the above examples, we are dealing with java.io.File Objects which are saved to a specified location. I dont want to save the image. Is there any way that I can use something similar to compress my Multipart Image file and continue with the upload.
Why don't you resize it on the client before upload? That will save some bandwidth
BlueImp JQuery Upload can do this
It was my first time taking a deep dive into the ImageIO package. I came across the MemoryCacheImageOutputStream, which allows you to write an image output stream to an output stream, i.e. ByteArrayOutputStream. From there, The data can be retrieved using toByteArray() and toString(), after compression. I used toByteArray, as I am storing images to postgresql and it stores the images as a byte array. I know this is late, but I hope it helps someone.
private byte[] compressImage(MultipartFile mpFile) {
float quality = 0.3f;
String imageName = mpFile.getOriginalFilename();
String imageExtension = imageName.substring(imageName.lastIndexOf(".") + 1);
// Returns an Iterator containing all currently registered ImageWriters that claim to be able to encode the named format.
// You don't have to register one yourself; some are provided.
ImageWriter imageWriter = ImageIO.getImageWritersByFormatName(imageExtension).next();
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // Check the api value that suites your needs.
// A compression quality setting of 0.0 is most generically interpreted as "high compression is important,"
// while a setting of 1.0 is most generically interpreted as "high image quality is important."
imageWriteParam.setCompressionQuality(quality);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// MemoryCacheImageOutputStream: An implementation of ImageOutputStream that writes its output to a regular
// OutputStream, i.e. the ByteArrayOutputStream.
ImageOutputStream imageOutputStream = new MemoryCacheImageOutputStream(baos);
// Sets the destination to the given ImageOutputStream or other Object.
imageWriter.setOutput(imageOutputStream);
BufferedImage originalImage = null;
try (InputStream inputStream = mpFile.getInputStream()) {
originalImage = ImageIO.read(inputStream);
} catch (IOException e) {
String info = String.format("compressImage - bufferedImage (file %s)- IOException - message: %s ", imageName, e.getMessage());
logger.error(info);
return baos.toByteArray();
}
IIOImage image = new IIOImage(originalImage, null, null);
try {
imageWriter.write(null, image, imageWriteParam);
} catch (IOException e) {
String info = String.format("compressImage - imageWriter (file %s)- IOException - message: %s ", imageName, e.getMessage());
logger.error(info);
} finally {
imageWriter.dispose();
}
return baos.toByteArray();
}

Error while converting image to byte[] in Java using WritableRaster and DataBufferByte.

I am trying to convert image to byte[] using code
public static byte[] extractBytes(String ImageName) throws IOException {
// open image
File imgPath = new File(ImageName);
BufferedImage bufferedImage = ImageIO.read(imgPath);
// get DataBufferBytes from Raster
WritableRaster raster = bufferedImage.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return (data.getData());
}
When I am testing it using code
public static void main(String[] args) throws IOException {
String filepath = "image_old.jpg";
byte[] data = extractBytes(filepath);
System.out.println(data.length);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
File outputfile = new File("image_new.jpg");
ImageIO.write(img, "jpeg", outputfile);
}
I am getting data.length = 4665600 and getting error
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1591)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
at com.medianet.hello.HbaseUtil.main(HbaseUtil.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
But when I am changing my extractBytes code to
public static byte[] extractBytes (String ImageName) throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedImage img=ImageIO.read(new File(ImageName));
ImageIO.write(img, "jpg", baos);
baos.flush();
return baos.toByteArray();
}
I am getting data.length = 120905 and getting success(image.jpg getting created in the desired location)
The thing is, the first version of extractBytes reads an image, and just returns the image's pixels as an array of bytes (assuming it uses DataBufferByte). These bytes are not in a file format, and are useless without extra information, such as width, height, color space etc. ImageIO can't read these bytes back, and because of this, null is returned (and assigned to img, later causing an IllegalArgumentException from ImageIO.write(...)).
The second version decodes the image, then encodes it again in JPEG format. This is a format ImageIO will be able to read, and you get an image (assigned to img) as you expect.
However, you code seems like just a very, very CPU-expensive way of copying images (you decode an image, then encode, then decode again, before finally encoding)... For JPEG files this decode/encode cycle will also degrade the image quality. Unless you are planning to use the image data for anything, and just want to copy an image from one place to another, don't use ImageIO and BufferedImages. These types are intended for image manipulation.
Here's a modified version of your main method:
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[1024];
File inFile = new File("image_old.jpg");
File outFile = new File("image_new.jpg");
InputStream in = new FileInputStream(inFile);
try {
OutputStream out = new FileOutputStream(outFile);
try {
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
finally {
out.close();
}
}
finally {
in.close();
}
}
(It's possible to write this better/more elegant using try-with-resources in Java 7, or NIO2 Files.copy in Java 8, but I leave that to you. :-) )

Using ImageIO to write JPEG 2000 with layers (i.e. decomposition levels)

Ok, here is our issue:
We are trying to convert a series of black and white .tiff files into jpeg2000 .jpf files, using imageio. We are always getting viewable .jpf files, but they usually do not have the specified number of layers or decomposition levels for zooming.
Here is our code:
//Get the tiff reader
Iterator<ImageReader> readerIterator = ImageIO.getImageReadersByFormatName("tiff");
ImageReader tiffreader = readerIterator.next();
//make an ImageInputStream from our tiff file and have the tiff reader read it
ImageInputStream iis = ImageIO.createImageInputStream(itemFile);
tiffreader.setInput(iis);
//just pass empty params to the tiff reader
ImageReadParam tparam;
tparam = new TIFFImageReadParam();
IIOImage img = tiffreader.readAll(0, tparam);
//set up target file
File f = new File(itemTargetDirectory.getAbsolutePath() + "/" + destFileName);
//we have tried FILTER_97 as well as different ProgressionTypes and compression settings
J2KImageWriteParam param;
param = new J2KImageWriteParam();
param.setProgressionType("layer");
param.setFilter(J2KImageWriteParam.FILTER_53);
//Our problem is that this param is not always respected in the resulting .jpf
param.setNumDecompositionLevels(5);
//get the JPEG 2000 writer
Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName("JPEG 2000");
J2KImageWriter jp2kwriter = null;
jp2kwriter = (J2KImageWriter) writerIterator.next();
//write the jpf file
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
jp2kwriter.setOutput(ios);
jp2kwriter.write(null, img, param);
It has been an odd experience, as the same code has behaved differently on subsequent runs.
Any insights will be appreciated!
Do all the TIFF files have the same settings (color model)? J2KImageWriter.java shows the decomposition levels getting set (forced) to zero when indexed-color or multi-pixel packed source images are used as input.
Drew was on the right track, and here is the code that ended up sorting things out for us:
public void compressor(String inputFile, String outputFile) throws IOException {
J2KImageWriteParam iwp = new J2KImageWriteParam();
FileInputStream fis = new FileInputStream(new File(inputFile));
BufferedImage image = ImageIO.read(fis);
fis.close();
if (image == null)
{
System.out.println("If no registered ImageReader claims to be able to read the resulting stream");
}
Iterator writers = ImageIO.getImageWritersByFormatName("JPEG2000");
String name = null;
ImageWriter writer = null;
while (name != "com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriter") {
writer = (ImageWriter) writers.next();
name = writer.getClass().getName();
System.out.println(name);
}
File f = new File(outputFile);
long s = System.currentTimeMillis();
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
writer.setOutput(ios);
J2KImageWriteParam param = (J2KImageWriteParam) writer.getDefaultWriteParam();
IIOImage ioimage = new IIOImage(image, null, null);
param.setSOP(true);
param.setWriteCodeStreamOnly(true);
param.setProgressionType("layer");
param.setLossless(false);
param.setCompressionMode(J2KImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("JPEG2000");
param.setCompressionQuality(0.1f);
param.setEncodingRate(1.01);
param.setFilter(J2KImageWriteParam.FILTER_97);
writer.write(null, ioimage, param);
System.out.println(System.currentTimeMillis() - s);
writer.dispose();
ios.flush();
ios.close();
image.flush();
}

Categories