Im trying to generate a QR code using QRGen, encode it in Base64 and insert it as an image in an HTML string. Later, the HTML string is decoded to be displayed in a JEditorPane (and then sent to a printer). To this end, the ImageView class is extended and a custom View factory is used. This all works fine... sometimes. It completely depends on the input string. Some strings work without issue, others fail cause the decode process to fail with the error java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit
.
Here is the encode process:
public BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
ByteArrayOutputStream stream = QRCode.from(barcodeText).to(ImageType.PNG).stream();
ByteArrayInputStream bis = new ByteArrayInputStream(stream.toByteArray());
return ImageIO.read(bis);
}
public static String encodeToString(BufferedImage image, String type) {
String imageString = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ImageIO.write(image, type, bos);
byte[] imageBytes = bos.toByteArray();
Base64.Encoder encoder = Base64.getEncoder();
imageString = encoder.encodeToString(imageBytes);
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
return imageString;
}
and the decode process:
private Image loadImage() {
String b64 = getBASE64Image();
BufferedImage newImage = null;
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(Base64.getDecoder().decode(b64.getBytes())); //fails here
newImage = ImageIO.read(bais);
} catch (Throwable ex) {
ex.printStackTrace();
}
return newImage;
}
@Override
public URL getImageURL() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (isBase64Encoded(src)) {
this.url = BASE64ImageView.class.getProtectionDomain()
.getCodeSource().getLocation();
return this.url;
}
return super.getImageURL();
}
private boolean isBase64Encoded(String src) {
return src != null && src.contains("base64,");
}
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
And here is the QR code in question that fails to decode.
<img width='30' height='30' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9AQAAAACn+1GIAAAApklEQVR4Xu2UMQ4EMQgD/QP+/0vK6zjsvayUMmavWxQpMAUBkwS12wcveAAkgNSCD3rR5Lkgoai3GUCMgWqbAEYR3HxAkZlzU/0MyBisYRsgI1ERFfcpBpA+ze6k56Cj7KTdXNigFWZvSOpsgqLfd18i2aAukXh9TXBNmdWt5gzA/oqzWkkN8HtA7G8CNOwYAiZt3wZixUfkA32OHNQq7Bxs9oI/gC/9fV8AVCkPjQAAAABJRU5ErkJggg=='/>
I did open the above QR in a browser (Chrome) and it does work, which definitely points to something being wrong in the decode process and not the encode process.
Found the issue. In getBASE64Image(), I have
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
The "-1" in the substring call was the cause of my problems. Not sure why this would work only sometimes, but removing seems to have fixed the problem.