0

I am getting corrupted image icon while displaying b64 encoded png image response from rest API.

javascript-

function getcap(){
            var http = new XMLHttpRequest()
            http.open("GET", "http://localhost:8888/newcaptcha",true)
            http.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
            http.setRequestHeader("Access-Control-Allow-Origin", "http://localhost:8888");
            http.send()
            http.onload = () => {   
                var resp=unescape(encodeURIComponent(http.responseText));
                var b64Response = window.btoa(resp);
                console.log('data:image/png;base64,'+b64Response);
                document.getElementById("capimg").src =  'data:image/png;base64,'+b64Response;
            }
        }

html -

<div id="newCaptcha" onClick="getcap()" ><h5>new captcha:</h5><img id="capimg" width="30" height ="30"/></div>

b64 encoded response-

server code -

@CrossOrigin(origins = "http://localhost:8080")
    @RequestMapping(value = "/newcaptcha", method = RequestMethod.GET, produces = "image/png")
    public @ResponseBody byte[] getnewCaptcha() {
         try {
                 Random random = new Random();
                 imgkey= random.nextInt(3);
                 InputStream is = this.getClass().getResourceAsStream("/"+captcheMap.get(imgkey)+".png"); 
                 BufferedImage img = ImageIO.read(is);
                 ByteArrayOutputStream bao = new ByteArrayOutputStream();
                 ImageIO.write(img, "png", bao);
                 return bao.toByteArray();   
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
    }
jinn
  • 61
  • 9

2 Answers2

0

The base 64 response attached doesn't seem to actually load the image, if I open it in browser. Secondly, I can see that that one problem that can cause this is reloading of DOM element img, if its not handled by any framework, you may have to manually intervene. To check this, you can test using a local image and load that. If it doesn't work, then you got your root cause. And if it does, then this base64 response is an issue. Also, check the console for any errors and do update here.

Abhi
  • 94
  • 7
0

As I pointed out in comments, probably you don't need b64. However, if you really want, read this.

There are tons on questions on Stackoverflow on this subject, and few answers. I have put together all pieces.

The point is that btoa() badly supports binary data.

Here: convert binary data to base-64 javaScript you find the suggestion to use arraybuffers as responseType, instead of just text.

Here: ArrayBuffer to base64 encoded string you find a function that converts arraybuffers to b64.

Putting all togheter:

function getcap(){
            var http = new XMLHttpRequest();
            http.open("GET", "/newcaptcha",true);
            http.responseType = 'arraybuffer';
            http.send();
            http.onload = () => {
                console.log(http.response);
                var b64Response = _arrayBufferToBase64(http.response);
                document.getElementById("capimg").src =  'data:image/png;base64,'+b64Response;
            }
        }

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
    return window.btoa( binary );
}
luca.vercelli
  • 898
  • 7
  • 24