How to save photos in full resolution in android? - java

I have made an app that uses the camera to capture images. The images are passed back to my application as Bitmap. I want to know how to modify my code to save the Bitmap into JPEG format at its full resolution?
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
I think the Bitmap is being compressed into smaller size!

Compression refers to the the reduction of physical disk space required to save the image. It doesn't automatically mean that the image quality or resolution is also reduced.
JPEG is part of a group of file formats that (mostly) belong to the lossy compression algorithms. In other words some minor image detail and quality is sacrificed to reduce the file size of the image, but it still wouldn't reduce the resolution of the image.
If you want to reduce the file size of the image, but don't want to loose any image quality you need to use a file format which supports lossless compression. You can for example use Bitmap.CompressFormat.PNG.
WEBP supports both lossy and lossless compression (and is even smaller than PNG and JPG in file size). But support for WEBP was only added in API level 14 so there might be some backwards compatibility problems. Just use WEBP if possible, otherwise PNG if you care about image quality.
In any case let's look at the compress() method:
public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream)
As you can see you can choose the CompressFormat, pass an OutputStream in and pick a quality. The number you pass in as quality can be between 0 and 100 and it determines if you compress either lossy or lossless. Since you pass in 100 the compression will always be lossless regardless of which CompressFormat you pick!
As an aside: Since PNG only supports lossless compression it will ignore the quality parameter completely and always save the image without reducing its quality!

Related

Lossless image extraction from PDF

I'm using PDFBox to extract images out of a PDF file and feed it to another image processing library (that can handle different image formats). My current code is like this:
PDImageXObject pdImage;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedImage image = pdImage.getImage();
ImageIO.write(image, "png", baos);
byte[] imageBytes = baos.toByteArray();
This will take whatever is stored in the PDF file and use Java graphics to convert it to PNG. Is there a better way to avoid conversion and extract the image in whatever format it is embedded? I don't want to degrade image quality (I suppose mitigated by using a lossless format like PNG?) and incur conversion overhead.
The DEFLATE algorithm is used by the FlateDecode filter and by the PNG file format. However a stream of FlateDecode-compressed data isn't itself a PNG file.
Also, you need to consider the colorspace representation of the Image XObject (e.g. DeviceCMYK) versus what PNG actually supports.
By targeting lossless compression for your output image file you won't lose any information. (Be sure you actually need a lossless extracted image, often people assume lossy compression means their image will now have so many changes it's no longer recognizable. Though in many cases depending on the parameters the loss is hardly noticeable to the naked eye and you can substantially benefit from the size savings of Lossy compression.)
If performance is slow it could simply be the quality of your PDF software responsible for extracting the image and saving it.

How to save lossless jpg in java?

I have to save a jpeg image lossless. I am work on a steganography project but Java compressing and saving my result. I research every forums and try everything but it didn't work.
Here my example code for lossless save a jpeg image:
BufferedImage image = ImageIO.read(new File("sources/image.jpg"));
ImageWriter writer = ImageIO.getImageWritersByFormatName("JPEG").next();
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
writer.setOutput(ImageIO.createImageOutputStream(new File("example.jpg")));
writer.write(null, new IIOImage(image,null,null), jpegParams);
writer.dispose();
After this process I compute PSNR value is 28.53173 and "example.jpg"'s size is bigger than "image.jpg".
I try import JAI library but I am not sure Java 8 is support JAI.
JPEG is lossy all the time. Even at 100% compression quality there will be some loss of information, but it will be minimised.
The reason why your example.jpg has a bigger size is because it was encoded with a 100% quality factor, while most jpeg encoders have a default value of 50%-75%, which is what was most likely used for example.jpg. You can try different quality factors to see when both files have the same size.
A lossless JPEG format does exist (available in JAI), but it should be thought of as a different format to the conventional JPEG. However, it's not widely used and you'll probably not be able to view it in most applications, which would practically defeat the point of sharing an innocent image.

Reducing image height and width by 50% but image size on disk remains the same

I am trying to reduce the size of the image by reszing its length and width but it stays the same size in megabytes sometimes its even larger even though its only half as big.
String compressPath = Environment.getExternalStorageDirectory()+"/test2.jpg";
FileInputStream in = new FileInputStream(path);
Bitmap fullSizeBitmap = BitmapFactory.decodeStream(in);
Bitmap resized = Bitmap.createScaledBitmap(
fullSizeBitmap,
(int)(fullSizeBitmap.getWidth()*0.5),
(int)(fullSizeBitmap.getHeight()*0.5),
true
);
FileOutputStream mOutputStream = new FileOutputStream(compressPath);
resized.compress(Bitmap.CompressFormat.PNG, 100, mOutputStream);
What's the problem? Do I have to lower the quality?
Per Bitmap's Android doc:
quality Hint to the compressor, 0-100. 0 meaning compress for small
size, 100 meaning compress for max quality. Some formats, like PNG
which is lossless, will ignore the quality setting
Your original input is JPG, but you are outputting it to PNG. Since JPG will always have quality degradation that introduce artifacts, making the generated PNG files larger when converted. Try saving it as JPG with 80-100 quality instead.
Also, in my tests compressing to PNG take 2-5x more time than compressing to JPG, due to PNG compression is done in software and JPG in hardware. So for most images it's probably better to compress to JPG.

How to get image compression quality from IIOMetadata?

When saving a new image with ImageIO generic ImageWriteParam supports explicit setting of compressionQuality parameter from range 0.0f (high compression) to 1.0f (high quality) regardless of image compression algorithm used (eg. png, jpeg, gif).
Is there any way to read compressionQuality from an existing image?
Is that compressionQuality write parameter just a hint to ImageWriter and is not stored anywhere in image's metadata? If that's true how image processing software (e.g. GIMP) manages to provide the following option in 'Save As' dialog?
I managed to read IIOMetadata from ImageInputStream and iterate through its metadataFormatNames to print out image metadata in different XML formats (native and standard javax_imageio_1.0, usually). Although I couldn't find any indication of image's compressionQuality in there.
I don't think that compressionQuality is stored with image meta data, this is processing parameter only.

Java: Send BufferedImage through Socket with a low bitdepth

The title says enough I think.
I have a full quality BufferedImage and I want to send it through an OutputStream with a low
bitdepth. I don't want an algorithm to change pixel by pixel the quality, so it is still a full-quality.
So, the goal is to write the image (with the full resolution, full size) through the OuputStream which takes a very little number of bytes to write.
Thanks,
Martijn
You need to encode the image data into the format that has the right characteristics for your image. If it's 24-bit color and has a lot of colors and you want to lose no quality, you are probably stuck with PNG, but look into lossless JPEG 2000.
If you can lose some quality, then try
Lossy JPEG 2000 -- much smaller than JPEG for the same quality loss
reducing the number of colors and using a color mapped format
If the image has only gray or black and white data, make sure that you are encoding it as such (8-bit gray or 1-bit black and white). Then, make sure you use an encoder that is tuned for that kind of format (for example TIFF with Group 4 or JBIG2).
Another good option is to remove all of the unwanted meta-data from the image (or make sure that your encoder doesn't put any in).
If you want to stick with what's in Java, you probably have to use TIFF, PNG or JPEG -- there are third party image endcoders (for example, my company, Atalasoft, makes a .NET version of these advanced encoders -- there are Java vendors out there as well)
FYI: reducing bit depth usually means reducing quality (unless the reduction is meaningless). For example if I have a 24-bit color image, but all of the colors are gray (where R==G==B), then reducing to 8-bit gray does not lose quality. This is also true if your image has any collection of 256 different colors and you switch to a color mapped (indexed or paletted) format. You reduce the number of bytes and don't reduce quality.
Have a look at the java.util.zip package for all about compression:
http://java.sun.com/developer/technicalArticles/Programming/compression/
Though JPEG and PNG are already somehow compressed, using the Inflater class, you can reduce byte count while maintaining the exact same quality of your image. Compressing an already compressed format generally are not significant. If you group several images together, though, inflating them is significant (since inflation techniques recognize common patterns in object data, which reduce repetition and thus reduces byte count).

Categories