I am currently working with Image processing in Java. Initially I used ImageIO class to write images
ImageIO.write(image,"jpg",os);
the problem with this method is am lossing the actual image size and quality. Then I preferred ByteStream
Files.readAllBytes(fi.toPath());
to read and
fos.write(fileContent);
to write Images. This works perfectly. The issue I am facing here is I can read only files but not Images(ie, BuffreredImage image). Is it possible to read a Image rather than files here or should I move to someother IO?
Code Snippet is here,
try {
File fnew=new File("d:\\3\\IMG1.jpg");
java.io.FileOutputStream fos = new java.io.FileOutputStream(new File("d:\\3\\Test1\\4.jpg"));
File fi = new File("d:\\3\\7.jpg");
byte[] fileContent = Files.readAllBytes(fi.toPath());
fos.write(fileContent);
} catch (Exception e) {
System.out.println("Exception");
}
Any Kind of suggestions or help will be appreciated. Thanks in Advance.
the problem with this method is am lossing the actual image size and quality. Then I preferred ByteStream
When you read a JPEG with with ImageIO, it is converting the JPEG to a Bitmap automatically. Then when you write it, it is encoding to a JPEG again (which loses quality).
Just replace ImageIO.write(image,"jpg",os) with ImageIO.write(image,"png",os) and you are done. A lossless format such as PNG will not lose any data when you write the image.
BufferedImage getRGB() will get you all the actual pixel data for the image. There will be no compression or anything like JPEG. It will be the raw image.
Edited to add an example based on my comments...
BufferedImage image = ImageIO.read(new File("google.jpg"));
ImageWriter w = ImageIO.getImageWritersBySuffix("jpg").next();
ImageOutputStream out = ImageIO.createImageOutputStream(new File("output.jpg"));
w.setOutput(out);
ImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1);
w.write(null, new IIOImage(image, null, null), param);
out.close();
Related
I want to compress(reduce) image size using Java. We can upload images in jpg/jpeg/png formats. The general format of images is PNG. So, after image uploaded to the server, we need to compress(reduce file size) and convert it to PNG.
I have the next code for the compress image:
BufferedImage bufferedImage = ImageIO.read(inputStream);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
switch (imageType) {
case PNG:
case JPG:
// need Java 9+ for PNG writer support
ImageWriter writer = ImageIO.getImageWritersByFormatName(imageType.getExtension()).next();
ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.3f);
}
writer.write(null, new IIOImage(bufferedImage, null, null), param);
writer.dispose();
return new ByteArrayInputStream(outputStream.toByteArray());
default:
log.warn("Image type unknown");
return null;
}
The problem is - after processing the image, I got the result - file size increased instead of reducing. The original image has a lower size than compressed.
Any suggestions on how to solve this issue?
Unfortunately the lossy JPEG compression compresses far better than the lossless PNG compression. You could restrict width and height of the image and scale proportionally.
So I would switch to JPEG and restrict the size.
As a solution for this problem I can recommend the API of TinyPNG.
You can use it for compressing as well as resizing the image.
It works for both .jpeg and .png.
Documentation: tinypng.com/developers/reference/java
I need to be able to modify the contents of a jpeg or png files and am able to successfully break the image down into bytes and vice versa. The only problem is that i do not know how many bytes make up a jpeg file header or a png file header. The information on most websites is pretty vague and/or way too informative for a beginner like me.
Id really appreciate if someone can provide a simple answer telling me how many bytes i need to skip to get past the header and how to identify if the image is a jpeg image or a png image as well as any other important information that i may not have mentioned.
Ive added the code below which im using to extract the bytes from an image and to convert the image into bytes.
Note: This code works on android OS
Code used to convert image to bytes:
public byte[] imgtobytes(File f)
{
FileInputStream fis=null;
try
{
fis = new FileInputStream(f);
}
catch(Exception e) {}
Bitmap bm = BitmapFactory.decodeStream(fis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100 , baos);
byte[] b = baos.toByteArray();
return b;
}
Code used to convert bytes to image and display it on an imageview:
public void bytestoimg(byte[] bytearray, ImageView imgv)
{
Bitmap bmp = BitmapFactory.decodeByteArray(bytearray, 0, bytearray.length);
imgv.setImageBitmap(Bitmap.createScaledBitmap(bmp, imgv.getWidth(),
imgv.getHeight(), false));
}
I've done some similar work in python a while ago playing with encryption. I believe that what you are looking for can be found in this wikipedia article under "Examples" section.
Also you can check out this answer
In JPEG images, EXIF metadata is sometimes included and tells in what orientation the image should be shown.
The question is, whether Java's ImageIO.read() takes EXIF into account while reading a JPEG image, and automatically applies the transformation.
More concretely, if I use Java's ImageIO for converting a JPEG image with EXIF into a PNG image, is the orientation of the PNG image going to be correct? Or is the below code going to produce a PNG image without taking EXIF orientation instructions into account?
private byte[] convertToPng(byte[] imageFileAsByteArray) {
ByteArrayInputStream bis = new ByteArrayInputStream(imageFileAsByteArray);
BufferedImage bi = ImageIO.read(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", bos);
return bos.toByteArray();
}
The short answer is, unfortunately, no; ImageIO.read(..) (by default) does not take the Exif Orientation tag into account. Your PNG will be not be rotated accordingly.
However, all ImageIO.read(..) does internally, is to look up an appropriate ImageReader plug-in for the input, and delegate reading to it. And while the JRE-bundled plug-in does not take Exif into account, it is possible to add support for it, in a third-party ImageReader. Unfortunately, I don't know of any that do, but I am considering adding Exif orientation support to the TwelveMonkeys ImageIO JPEGImageReader in the future.
In the mean time, you have to apply the rotation yourself, by reading the metadata and rotating. The value of the orientation tag can be acquired either using the ImageIO JPEG metadata or some third-party library. I think both the mentioned metadata-extractor or TwelveMonkeys ImageIO can be used for this purpose. JAI ImageIO (using the TIFF metadata) can probably also do this.
If using the ImageIO JPEG metadata, be aware:
Note that an application wishing to interpret Exif metadata given a metadata tree structure in the javax_imageio_jpeg_image_1.0 format must check for an unknown marker segment with a tag indicating an APP1 marker and containing data identifying it as an Exif marker segment.
I have struggled with jpeg exif orientation for awhile, and now that I set out to fix my problems, I find that they are gone. To make sure for myself, I simplified OP.s example so as to read
public static void main (String [] args) throws Exception {
java.io.File in = new java.io.File ("in.jpg");
java.io.File out = new java.io.File ("out.png");
BufferedImage image = ImageIO.read (new FileInputStream(in));
ImageIO.write (image, "png", out);
}
in.jpg is a picture with exif orientation tag 8, tilted to the left. When I run the example, out.png is created as a properly oriented png picture. So it seems that ImageIo has learned something recently.
I am trying to insert a 1 MB image inside neo4j using the following code:
File fnew = new File("C:\\Users\\myimage.jpg");
BufferedImage originalImage = ImageIO.read(fnew);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.flus();
ImageIO.write(originalImage, "jpg", baos);
return baos.toByteArray();
Then I insert this byte array using:
user.setProperty("photo", photo);
This all goes fine. When I try to select the photo, using the following method, it writes it on my hard drive disk as 536KB instead of the 1 MB original size.
byte[] imageInByte = (byte[]) user.getProperty("photo");
InputStream in = new ByteArrayInputStream(imageInByte);
BufferedImage bImageFromConvert = ImageIO.read(in);
ImageIO.write(bImageFromConvert, "jpg", new File("C:\\newimage.jpg"));
Now the weird part: I can see the image, open it, same resolution, I don't see any difference in terms of quality though. Looks like it is compressed.
Why is this happening?
Saving a jpg image through ImageIO results in lossy compression of the jpg (I believe the quality defaults to 70%). You can a) Change the the quality of the image when you write to file (see Setting jpg compression level with ImageIO in Java ) or b) if you don't actually need the BufferedImage, just read/write the bytes from file to database.
I'm trying to convert a bitmap image into an uncompressed tif file for use with the Tesseract OCR engine.
I can use this method to produce a compressed tif file...
final BufferedImage bmp = ImageIO.read(new File("input.bmp"));
ImageIO.write(bmp, "jpg", new File("output.tif"));
This produces an empty tif file when the "jpg" is changed to tif as these files are dealt with in Java Advanced Imaging (JAI).
How can I create an uncompressed tif image? Should I decompress the tif image produced from the above code or is there another way to handle the conversion process?
Any examples provided would be much appreciated.
Thanks
kingh32
You can use ImageWriteParam to disable compression:
TIFFImageWriterSpi spi = new TIFFImageWriterSpi();
ImageWriter writer = spi.createWriterInstance();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_DISABLED);
ImageOutputStream ios = ImageIO.createImageOutputStream(new File("output.tif"));
writer.setOutput(ios);
writer.write(null, new IIOImage(bmp, null, null), param);
Some time before i was facing the problems with tiff images reading and conversion with jai.
I found that it need to install support for working with tiff images in jai, then it works fine for me u can also get it form here:
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=jaiio-1.0_01-oth-JPR#CDS-CDS_Developer
and install over a jvm then it will also work for you.
you can also have a look here
Java / JAI - save an image gray-scaled