Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Data-URL to BufferedImage

I have a Data-URL from an image file and have to pass it through to another function. Along this path from Data-URL to the BufferedImage it needs to be a byteArray.

my approach was the following:

String dataUrl;
byte[] imageData = dataUrl.getBytes();

// pass the byteArray along the path

// create BufferedImage from byteArray
BufferedImage inputImage = ImageIO.read(new ByteArrayInputStream(imageData));

// If the picture is null, then throw an unsupported image exception.
if (inputImage == null) {
    throw new UnknownImageFormatException();
}

The problem is, it always throws the UnknownImageFormatException Exception, which means inputImage is null, which means, the ImageIO.read did not recognize the imagetype.

I've used ImageIO.getReaderFormatNames() to get the supported Filenames and got the following list:

Supported Formats: 
jpg, BMP, bmp, JPG, jpeg, wbmp, png, JPEG, PNG, WBMP, GIF, gif

The dataURLs I try to pass are like: data:image/png;base64,... or data:image/jpg;base64,...

As far as I understand, those are in the supported filelist and therefor should be recognized.

What else could cause the inputImage to be null in this case? And more interesting, how do I solve it?

like image 866
Daniel Avatar asked Sep 02 '13 09:09

Daniel


3 Answers

As the comments already said the image data is Base64 encoded. To retrieve the binary data you have to strip the type/encoding headers, then decode the Base64 content to binary data.

String encodingPrefix = "base64,";
int contentStartIndex = dataUrl.indexOf(encodingPrefix) + encodingPrefix.length();
byte[] imageData = Base64.decodeBase64(dataUrl.substring(contentStartIndex));

I use org.apache.commons.codec.binary.Base64 from apaches common-codec, other Base64 decoders should work as well.

like image 162
ChristophT Avatar answered Nov 08 '22 15:11

ChristophT


The only one problem with RFC2397 string is its specification with everything before data but data: and , optional:

data:[<mediatype>][;base64],<data>

So pure Java 8 solution accounting this would be:

final int dataStartIndex = dataUrl.indexOf(",") + 1;
final String data = dataUrl.substring(dataStartIndex);
byte[] decoded = java.util.Base64.getDecoder().decode(data);

Of course dataStartIndex should be checked.

like image 34
Roman Nikitchenko Avatar answered Nov 08 '22 15:11

Roman Nikitchenko


I think, a simple regex replace would be better and more conform to the RFC2397:

java.util.Base64.getDecoder().decode(b64DataString.replaceFirst("data:.+,", ""))

The RFC states that the data: and the , are the required prefixes for a data url, therefore it is wise to match for them.

like image 2
nyuwec Avatar answered Nov 08 '22 16:11

nyuwec