How to rotate a jpeg lossless (90, 180, 270, 360) [duplicate] - java

This question already has answers here:
Lossless JPEG Rotate (90/180/270 degrees) in Java?
(5 answers)
Closed 8 years ago.
I want to rotate an jpeg image lossless.
My code works with success but is with loss:
ByteArrayInputStream inputstream = new ByteArrayInputStream(imgByteArraySource);
BufferedImage oldBufferedImage = ImageIO.read(inputstream);
BufferedImage newBufferedImage = rotate(oldBufferedImage, degrees);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newBufferedImage, "jpg", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
I found an old post on this site:
Lossless JPEG Rotate (90/180/270 degrees) in Java?
Maybe there is a better solution.
I'm not very confident about the media-util library (it is old, and it is packaged in a .exe file).
Has someone an idea?
Is there a new and better way to do this?
Thanks in advance.
Bobby

It is only possible to rotate losslessly in 90 degree increments.
To do it in 90 increments, you need to either compress using the same quantization tables used in the original (which still may introduce loss, depending upon the encoder) or use a special program that rearranges the MCUs in the JPEG stream.
Any time you decompress a JPEG using different quantization tables you will get loss.

Related

Java - reading a compressed bitmap

I'm looking to read in the RGB values of a bitmap (or the hex colour codes, either work).
I have tried both this code :
File image = serverConfig.get(map.bmp);
BufferedImage buffer = ImageIO.read(image);
dimX = buffer.getWidth();
dimY = buffer.getHeight();
byte[] pixlesB = (byte[]) buffer.getRaster().getDataElements(0, 0, buffer.getWidth(), buffer.getHeight(), null);
and this code :
File image = serverConfig.get(map.bmp);
BufferedImage buffer = ImageIO.read(image);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(buffer, "bmp", baos );
baos.flush();
byte[] pixlesB = baos.toByteArray();
baos.close();
The both work fine for a small bitmap, but when I load a large bitmap, the data gets compressed and the array returns a bunch of semi random numbers.
for example:
A green pixel will read 2,2,2 instead of 0,255,0
A red pixel will read 5,5,5 instead of 255,0,0
A yellow pixel will read 8,8,8 instead of 255,255,0
The bitmaps I'm using only include the colours red, yellow and green.
My problem is I have no way of knowing what colour 2,2,2 relates to without checking it manually (which I cannot do since it changes with each bitmap)
I know that there is some metadata in the bitmap that specifies 2 is green, but I don't know how to access it or use it to turn 2 back into 0,255,0
And this is not a duplicate of Java - get pixel array from image since that doesn't mention compressed files.
And while I did ask this question a while back, it was just redirected to the above site.
Thanks in advance!
EDIT: Just thought this might make the question a bit clearer. I believe the file is being read correctly, it is just compressed. How do I decompress it?
If you want to read an image as a bitmap or as rgb values, you need to transform the image's format first.
Jpeg is a compressed image format, you need to use a tool or library in order to read as rgb.
check this answer:
How to get the rgb values of a jpeg image in TYPE_3BYTE_BGR?
Hope this helps

Converting Image to Base64 string. Loss of Exif Metadata?

Hi so I have been working at this for a few days and i'm wondering if the way I am converting the images on the device is causing a loss of the metadata?
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
encodedImage = Base64.encodeToString(byteArrayImage,Base64.DEFAULT);
Is what I have to encode the image before it uploads to the database. Am I doing something that would cause the image to lose the metadata? In particular the date of image creation? I have read that using Java.io can cause this but I am unsure of another approach to take.
Any help hints pointers would be appreciated.

How to prevent loss of image quality while using ImageIO.write() method?

I am dealing with Images in java where I do read and write Images in my local disk. My Problem is while writing Images I am losing the quality of the actual Image I read. It reduces the quality by image file size from 6.19MB(actual image size) file to 1.22MB(written using ImageIO.write() which is drastic loss. How can I prevent this loss when i do use
ImageIO.write(image, "jpg", os);
for writing Image.
Remember, I dont need any compression over here. Just I want to read the Image and write the same image with same quality and same file Size. I also tried,
writer.write(null, new IIOImage(image, null, null), param);
but it takes my execution time more and does a compression process.
Please help me out in this. Is there any chance to write lossless image quality using
ImageIO.write(image, "jpg", os);
or any other way?
Thanks in advance...!
You seem to be a little confused about JPEG "compression" and "quality" (and I partly blame the ImageIO API for that, as they named the setting "compressionQuality").
JPEG is always going to compress. That's the point of the format. If you don't want compression, JPEG is not the format you want to use. Try uncompressed TIFF or BMP. As the commenters have already said, normal JPEG is always going to be lossy (JPEG-LS and JPEG Lossless are really different algorithms btw).
If you still want to go with JPEG, here's some help. Unfortunately, there's no way to control the "compressionQuality" setting using:
ImageIO.write(image, "jpg", os);
You need to use the more verbose form:
ImageReader reader = ...;
reader.setInput(...);
IIOImage image = reader.readAll(0, null); // Important, also read metadata
RenderedImage renderedImage = image.getRenderedImage();
// Modify renderedImage as you like
ImageWriter writer = ImageIO.getImageWriter(reader);
ImageWriteParam param = writer.getDefaultWriteParam();
paran.setCompressionMode(MODE_COPY_FROM_METADATA); // This modes ensures closest to original compression
writer.setOutput(...);
writer.write(null, image, param); // Write image along with original meta data
Note: try/finally blocks and stream close()and reader/writer dispose() omitted for clarity. You'll want them in real code. :-)
And this shouldn't really make your execution time noticeably longer, as ImageIO.write(...) uses similar code internally.

Convert BufferedImage to byte[] without losing quality and increasing size

I am trying to convert a BufferedImage to a byte array. I have two conditions. 1. I should not lose the quality of the image. 2. The size of the byte array should be the same as the actual image. I tried a couple of options.
Option 1:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
baos.flush();
byte[] imageBytes = baos.toByteArray();
baos.close();
Option 2:
WritableRaster raster = image.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
byte[] imageBytes = data.getData();
Both these options increase the size of the image (more than twofold for large images).
Appreciate any help. Thanks!
The PNG format uses lossless data compression, so you shouldn't need to worry about loosing the quality of the image with your option 1.
How are you seeing an increase in the size of the image? I'm sure you know what imageBytes.length is. What are you comparing this to that you're thinking this is twice as large as it should be? (I'm thinking your assumption may be incorrect.)
It is possible that your original source file is just using a higher compression setting than Java is re-compressing it with. You may need to pass some additional parameters into your writer. See how to compress a PNG image using Java for some additional details - specifically the link to http://www.exampledepot.com/egs/javax.imageio/JpegWrite.html.

Problem converting PNG to JPG using Java (ImageIO.write()) [duplicate]

This question already has answers here:
Issue using ImageIO.write jpg file: pink background [closed]
(6 answers)
Closed 9 years ago.
I am using ImageIO.write() to convert PNG files to JPG. For some reason, my result image has a pink layer over it. I have searched far and wide for a solution but haven't found any. The code works for all other types of images except PNG.
I'm not sure how the other code snippet works given buffer is not used after it's created. I've found this pink problem to be jvm version specific.
The easiest solution I've found is to do this.
BufferedImage image = null;
BufferedImage imageRGB = null;
// imageBytes is some png file you read
image = ImageIO.read(new ByteArrayInputStream(imageBytes));
// Attempt at PNG read fix
imageRGB = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_INT_RGB);
// write data into an RGB buffered image, no transparency
imageRGB.setData(image.getData());
// return the RGB buffered image, or do ImageIO.write( ... );
return imageRGB; // fixed for jpeg
Quick reading of other SO answers tagged ImageIO led to this.
The root cause can be a buggy reader. The proposed workaround is using different reader package.
Edit Above link is broken, but this appears to be it.
Edit The above links are broken, here it is on archive.org.
I too had the same problem, but if i write it in png format then it gets solved.
Something like this,
ImageIO.write(resizedImageBuffer, "png", baos);
I found this link which has some code that might be of use. I tried your code with a few of my images but I couldn't reproduce the issue. I tried the last answer by devyn_a and it didn't break anything. Here's your code modified with devyn_a's solution.
String url = "file:///d:/teststuff/IMG_0393.JPG";
String to = "d:/teststuff/out.jpg";
BufferedImage oldImage = ImageIO.read(new URL(url));
BufferedImage buffer = new BufferedImage (oldImage.getWidth(),
oldImage.getHeight(), BufferedImage.TYPE_INT_RGB);
ImageIO.write(ImageIO.read(new URL(url)), "jpg", new File(to));
It would be interesting to know if this resolves the issue.

Categories