Can't open image after decoding and writing to disk - java

I am uploading a jpg to a spring controller endpoint. The image is uploaded as Base64 image/jpg which comes in as a MultipartFile. I am decoding the inputstream using Base64Decoder which seems to decode it ok but when I turn it into an InputStream to write it out to disk I can see it's been modified (according to what I can see in the debugger). When I save the file and open it it says it's an unsupported file type.
I took the multipart inputstream and wrote it directly to disk and I see the base64 encoding in notepad.
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4QBgRXhpZgAASUkqAAgAAAACADEBAgAHAAAAJgAAAGmHBAABAAAALgAAAAAAAABHb29nbGUAAAMAAJAHAAQAAAAwMjIwAqAEAAEAAAAACAAAA6AEAAEAAAAABgAAAAAAAP/bAIQAAwICCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCggKCgoKCgoICAgKCgoICAgICgoICAgKCgoICA0NCggNCAgKCAEDBAQGBQYIBgYICA0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI/8AAEQgGAAgAAwEiAAIRAQMRAf/EAB0AAAIDAQEBAQEAAAAAAAAAAAMEAgUGAQAHCAn/xABJEAABAwIDBgQFBAIBAwMCAA8BAAIRAyEEMUEFElFhcfAGgZGhEyKxwdEHMuHxFEJSFSNiCDNyFoKSFyRDU6LCCTRjRHOy0uL/xAAbAQEBAQEBAQEBAAAAAAAAAAAAAQIDBAUGB//EACoRAQEBAQACAwADAAEEAwEBAQABEQIDcRIhMQQTsVEUIjJBBWGBwUIj/9oADAMBAAIRAxEAPwCgrFsRw4ZfWEs2FXUN4C7p4c10702ML4/M+p6jhzfqep/i4p0uS9Vtw8vddwRkX7t+ck1TdElWusVNVsRY3K1ngx2YFsz5rMYytJHX+7rSeDWGf6XHqf8A0938eZ02zK8LlWoMzwP9LwCV2jxC81j7kswTAYsE2Xto1OAzVPslvzHT8K8LV
Here's my controller and my code:
#PostMapping(value = "/saveBlueprintOrder")
public ResponseEntity<?> saveBlueprintOrder(#RequestParam MultipartFile blueprint,
#RequestParam(required = false) MultipartFile coversheet,
#RequestParam(required = false) MultipartFile logo,
#ModelAttribute BlueprintOrder blueprintOrder) {
if(coversheet != null) {
BASE64Decoder decoder1 = new BASE64Decoder();
byte[] imageBytes = decoder1.decodeBuffer(coversheet.getInputStream());
InputStream bis = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(bis);
ImageIO.write(image, "jpg", new File("C:\\Users\\i58287\\Downloads\\coversheet.jpg"));
OutputStream stream = new FileOutputStream("C:\\Users\\i58287\\Downloads\\coversheet-test.jpg");
stream.write(imageBytes);
stream.close();
I just need to be able to translate this image to an inputstream so I can check the image locally in addition I need to send it to another api as such. What am I missing that's causing this image to be un-openable? Thanks for any help!
PS: I've done a lot of combinations so this is showing a couple options I have tried, BufferedImage image = ImageIO.read(bis) keeps returning a null image.

Ok so I don't know WHY this is what I had to do but I ended up saving my byte[] as a String and cut off the pre-pended
data:image/jpeg;base64
Then I decoded it into an InputStream. Anyone know why I had to do this?
Here's the code:
String imageBytes = new String(coversheet.getBytes(), StandardCharsets.UTF_8);
String imageDataBytes = imageBytes.substring(imageBytes.indexOf(",") + 1);
InputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(imageDataBytes.getBytes()));
BufferedImage image = ImageIO.read(stream);
ImageIO.write(image, "jpg", new File("C:\\Users\\i58287\\Downloads\\coversheet-test.jpg"));

Related

can't create a image file from BASE64

Well, i'm trying to send a picture from android to java, if i make it with compression it works really good, but i need to make it without compression beacuse i need a good or normal quality.
FixBitmap is my current Bitmap picture
//Android
FixBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byteArray = byteArrayOutputStream.toByteArray();
ConvertImage = Base64.encodeToString(byteArray, Base64.DEFAULT);
Log.e(TAG,"LENGTH"+ConvertImage.length());
Length 43388
//Java
try{
String file=request.getParameter("image_data");
String filename=rt.getId()+"_"+rt.getName()+".png";
BufferedImage image = null;
byte[] imageByte;
BASE64Decoder decoder = new BASE64Decoder();
imageByte = decoder.decodeBuffer(file);
ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
image = ImageIO.read(bis);
bis.close();
File outputfile = new File(filename);
ImageIO.write(image, "png", outputfile);
Path destinationFile = Paths.get(getServletContext().getRealPath("/")+"uploads\\", filename);
Files.write(destinationFile,imageByte);
}catch(Exception ex){
System.out.println("Error :"+ex.getMessage());
}
This code actually works as i said, but the compression make it looks in a very bad quality, so i tried to make it without compression, just converting my bitmap to a byte array, just like this
ByteBuffer buffer = ByteBuffer.allocate(FixBitmap.getRowBytes() *
FixBitmap.getHeight());
FixBitmap.copyPixelsToBuffer(buffer);
byteArray = buffer.array();
ConvertImage = Base64.encodeToString(byteArray, Base64.DEFAULT);
Log.e(TAG,"LENGTH"+ConvertImage.length());
Length 252107
The code on my java side it's the same but now it doesn't work, it just shows me this error :
java.lang.IllegalArgumentException: image == null!
So I decided to print the length because maybe there is some restrictions about this...
so I hope you can help me with this (just send/get the picture without compression)

Convert BufferedImage to aws...rekognition.model.Image

I'm playing around with the Amazon Rekognition. I found a really nice/easy library to take an image from my webcam which works like this:
BufferedImage bufImg = webcam.getImage();
I'm then trying to convert this BufferedImage to a com.amazonaws.services.rekognition.model.Image , which is what must be submitted to the Rekognition library. This is what I'm doing:
byte[] imgBytes = ((DataBufferByte) bufImg.getData().getDataBuffer()).getData();
ByteBuffer byteBuffer = ByteBuffer.wrap(imgBytes);
return new Image().withBytes(byteBuffer);
However when I try and do some API call to Rekognition with the Image, I get an Exception:
com.amazonaws.services.rekognition.model.InvalidImageFormatException: Invalid image encoding (Service: AmazonRekognition; Status Code: 400; Error Code: InvalidImageFormatException; Request ID: X)
The docs state that the Java SDK will automatically base64 encode the bytes. In case, something weird was happening, I tried base64 encoding the bytes before converting:
imgBytes = Base64.getEncoder().encode(imgBytes);
However, the same Exception ensues.
Any ideas? :)
I tried encoding the image to a JPG (Rekognition supports PNG or JPG formats) and it solved the problem.
BufferedImage bufImg = webcam.getImage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bufImg, "jpg", baos);
ByteBuffer byteBuffer = ByteBuffer.wrap(baos.toByteArray());
return new Image().withBytes(byteBuffer);

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();
}

Java Converting ByteArray into Image

I'm reading a file that has an array of bytes. I downloaded the Apache Commons IO library to use the FileUtils' method readFileToByteArray
File file = new File("/home/username/array.txt");
FileUtils fu = new FileUtils();
byte[] array = FileUtils.readFileToByteArray(file);
I want to convert the array of bytes to an Image.
ByteArrayInputStream bis = new ByteArrayInputStream(array);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("gif");
ImageReader reader = (ImageReader) readers.next();
Object source = bis;
ImageInputStream iis = ImageIO.createImageInputStream(source);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
Image image = reader.read(0, param); // this line is the problem
When the code goes to the referred line, it throws an Exception saying
javax.imageio.IIOException: Unexpected block type 128!
I don't know what this exception means, therefore, I don't know how to fix it.
Any further information that could be helpful just need to be requested.
Thanks
I've tried your code on this file and it works fine.
What's the format of your array.txt? readFileToByteArray() expects a binary format, and your image reader will further expect it to be a GIF file.
Once you have byte[] you can use ImageIO to write it to BufferedImage.
BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(array));
ImageIO.write(bImageFromConvert, "gif", new File("c:/test.gif"));
That code means the reader couldn't decipher the metadata on the image file. Make sure the right file is getting read and it's well formed. Or it may be expecting a different file type.
without byte[] i feel this will be good for multipart file transfer,for this we need apache common jar files
final FileOutputStream output = new FileOutputStream("D:\\Dir\\"+ request.getParameter("imageName") + ".jpg");
IOUtils.copy(request.getPart("file").getInputStream(), output);
output.close();

How to get base64 encoded contents for an ImageReader?

How do I read an image into a base64 encoded string by its ImageReader?
Here's example source code using HtmlUnit. I want to get the base64 String of img:
WebClient wc = new WebClient();
wc.setThrowExceptionOnFailingStatusCode(false);
wc.setThrowExceptionOnScriptError(false);
HtmlPage p = wc.getPage("http://flickr.com");
HtmlImage img = (HtmlImage) p.getByXPath("//img").get(3);
System.out.println(img.getImageReader().getFormatName());
The HtmlUnit's HtmlImage#getImageReader() returns javax.imageio.ImageReader which is part of standard Java 2D API. You can get an BufferedImage out of it which you in turn can write to an OutputStream of any flavor using ImageIO#write().
The Apache Commons Codec has a Base64OutputStream which you can just decorate your OutputStream with.
HtmlImage img = (HtmlImage) p.getByXPath("//img").get(3);
ImageReader imageReader = img.getImageReader();
BufferedImage bufferedImage = imageReader.read(0);
String formatName = imageReader.getFormatName();
ByteArrayOutputStream byteaOutput = new ByteArrayOutputStream();
Base64OutputStream base64Output = new base64OutputStream(byteaOutput);
ImageIO.write(bufferedImage, formatName, base64output);
String base64 = new String(byteaOutput.toByteArray());
Or if you want to write it to file directly:
// ...
FileOutputStream fileOutput = new FileOutputStream("/base64.txt");
Base64OutputStream base64Output = new base64OutputStream(fileOutput);
ImageIO.write(bufferedImage, formatName, base64output);
I'm not quite sure what exactly you want.
But what about creating your own Reader (see javax.imageio.stream.ImageInputStreamImpl), containing the Base64-stuff?
Maybe this external free Base64Encoder can help you out.
Something that could be used like this in the end?
WebClient wc = new WebClient();
wc.setThrowExceptionOnFailingStatusCode(false);
wc.setThrowExceptionOnScriptError(false);
HtmlPage p = wc.getPage("http://flickr.com");
HtmlImage img = (HtmlImage) p.getByXPath("//img").get(3);
MyBase64EncodingReader reader = new MyBase64EncodingReader(img);
System.out.println(reader.toString());
You could use one of the encodeBase64 methods
from apache commons codec.
and create a string from the resulting byte array using the String(bytes[]) constructor.

Categories