18

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?

Daniel
  • 293
  • 1
  • 6
  • 15
  • 3
    You need to decode the String from base64 back to a binary format that ImageIO can read, or, if your have an URL object, maybe pass it directly to ImageIO – MadProgrammer Sep 02 '13 at 09:26
  • 2
    Further to the advice of @MadProgrammer you might use the [`DatatypeConverter`](http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/DatatypeConverter.html#method_summary) to convert the base 64 string back to a `byte[]`. – Andrew Thompson Sep 02 '13 at 09:42
  • See also [Any RFC 2397 Data URI Parser for Java?](https://stackoverflow.com/questions/12353552/any-rfc-2397-data-uri-parser-for-java) – Vadzim Oct 21 '20 at 15:51

3 Answers3

25

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.

ChristophT
  • 510
  • 5
  • 10
  • 8
    As of Java 8, there is a Base64 encoder/decoder in the core JDK: http://download.java.net/jdk8/docs/api/java/util/Base64.html – Jules Jan 29 '14 at 07:14
12

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.

Roman Nikitchenko
  • 12,800
  • 7
  • 74
  • 110
2

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.

Community
  • 1
  • 1
nyuwec
  • 481
  • 4
  • 12