31

Is it possible to display an image returned by jQuery AJAX call, in the main stream of your HTML?

I have a script that draws an image with a header (image/PNG). When I simply call it in the browser, the image is displayed.

But when I make an AJAX call with jQuery on this script, I can't display a clean image, I have something with a lot of strange symbols. This is my script that makes the image with a header (image/PNG).

#!/usr/bin/perl 

use strict;
use CGI;
use Template;
use CGI::Carp qw(fatalsToBrowser);
use lib qw(lib);
use GD;

my $cgi    = new CGI;

my $id_projet            =  $cgi   -> param('id_projet') ;      # 

# Create a new image
my $image = new GD::Image(985,60) || die;
my $red =  $image->colorAllocate(255, 0, 0);
my $black =  $image->colorAllocate(0, 0, 0);

$image->rectangle(0,0,984,59,$black);
$image->string(gdSmallFont,2,10,"Hello $id_projet ",$black);
# Output the image to the browser

print $cgi -> header({-type => 'image/png',-expires => '1d'});

#binmode STDOUT;

print $image->png;

Then I have my main script with an AJAX call inside:

  <script type="text/javascript" > 

  $(document).ready( function() { 

  $.ajax({
  type: "POST",
  url:'get_image_probes_via_ajax.pl',
  contentType: "image/png",
  data: "id_projet=[% visual.projet.id %]",
  success: function(data){
  $('.div_imagetranscrits').html('<img src="' + data + '" />'); },
 } );

 </script>  

In my HTML file I have one div with class="div_imagetranscrits" to be filled with my image.

I don't see what I'm doing wrong. The other solution is to make my script write the image on disk and just get the path to include in the src to display it. But I was thinking it was possible to get the image with an image/PNG header directly from an AJAX request.

Dmitry Shvedov
  • 3,169
  • 4
  • 39
  • 51
ZheFrench
  • 1,164
  • 3
  • 22
  • 46

5 Answers5

43

You'll need to send the image back base64 encoded, look at this: http://php.net/manual/en/function.base64-encode.php

Then in your ajax call change the success function to this:

$('.div_imagetranscrits').html('<img src="data:image/png;base64,' + data + '" />');
Timm
  • 12,553
  • 4
  • 31
  • 43
  • Yes i just found out ! That works great , thanks. But now If you want to call your script in the browser, it wont works unless you made a trick in your code with get params...for param('mode')=1 you encode, and if param('mode') is not defined you print simply your image/png header...anyway. Now it's works it's great . I found this way too,[jquery topic loading image ajax](http://forum.jquery.com/topic/loading-image-with-ajax) but my point is that's ugly. Your method is much better . thanks. – ZheFrench May 29 '12 at 16:27
  • 1
    Try `data:image/jpeg;base64` in place of `data:image/png;base64` – Timm Jul 30 '14 at 08:50
  • Update (2022): You no longer need to convert to base64. See my answer for example. – CaptainCodeman May 15 '22 at 18:37
21

Method 1

You should not make an ajax call, just put the src of the img element as the url of the image.

This would be useful if you use GET instead of POST

<script type="text/javascript" > 

  $(document).ready( function() { 
      $('.div_imagetranscrits').html('<img src="get_image_probes_via_ajax.pl?id_project=xxx" />')
  } );

</script>

Method 2

If you want to POST to that image and do it the way you do (trying to parse the contents of the image on the client side, you could try something like this: http://en.wikipedia.org/wiki/Data_URI_scheme

You'll need to encode the data to base64, then you could put data:[<MIME-type>][;charset=<encoding>][;base64],<data> into the img src

as example:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot img" />

To encode to base64:

Community
  • 1
  • 1
jperelli
  • 6,988
  • 5
  • 50
  • 85
8

This allows you to just get the image data and set to the img src, which is cool.

var oReq = new XMLHttpRequest();
oReq.open("post", '/somelocation/getmypic', true );        
oReq.responseType = "blob";
oReq.onload = function ( oEvent )
{
    var blob = oReq.response;
    var imgSrc = URL.createObjectURL( blob );                        
    var $img = $( '<img/>', {                
        "alt": "test image",
        "src": imgSrc
    } ).appendTo( $( '#bb_theImageContainer' ) );
    window.URL.revokeObjectURL( imgSrc );
};
oReq.send( null );

The basic idea is that the data is returned untampered with, it is placed in a blob and then a url is created to that object in memory. See here and here. Note supported browsers.

Community
  • 1
  • 1
acarlon
  • 16,764
  • 7
  • 75
  • 94
  • 1
    "Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided." – BUKTOP Jun 16 '16 at 12:02
  • @BbIKTOP: You're using some crusty old browser, perhaps? http://caniuse.com/#feat=bloburls – Michael Scheper Jul 15 '16 at 12:03
  • @Michael Scheper It was one month ago, I do not remember what browser it was. I use latest chrome, ff, safari and ie in win7 for testing, so, probably, it was one of them ) Anyway, usually developers cannot rely on a fact that all users have the latest versions. So, I'd like to advise src="data:image/png;base64,"+request.response method – BUKTOP Jul 17 '16 at 13:50
  • @BbIKTOP: If such cases are 'usual' for you, fair enough. But I was hoping to help find out why this solution didn't work for you, since it does for me. Many projects these days are for intranet use, and allow specifications like 'We do not support IE'. For those, it seems this answer is a winner. – Michael Scheper Jul 19 '16 at 08:37
  • @Michael Scheper Not for me actually, but for corporate clients it's so usual thing, be glad that you never did a big projects for big corporations ;) – BUKTOP Jul 27 '16 at 03:14
  • @BbIKTOP: Oh, I've done big projects for a pretty big (50,000+ employee) corporation, but I suppose I should feel glad it had a competent CTO. – Michael Scheper Aug 01 '16 at 13:42
  • Thank you, this is brilliant! It worked perfect for me. My implementation used a REST API to get the image so I had to include some request headers: oReq.setRequestHeader("Access-Control-Allow-Origin", "*"); and some others that Chrome Postman gave me. – gadildafissh Jul 31 '17 at 21:37
0

Thanks to above answers and after some more searching able to come up with below solution for Spring Boot application.

HTML

<div class="row">
     <div class="col-11" id='img_div'>
     </div>
</div>

Javascript

function loadImage() {

        $.ajax({
            type: "GET",
            url: contextPath+"/loadImage",
            data: null,
            dataType: 'text',
            cache: false,
            timeout: 600000,
            success: function (data) {
                $('#img_div').html('<img id="img" src="data:image/png;base64,' + data + '" />');
                
            },
            error: function (e) {
                //handle error
            }
        });
    
    }

Controller Method

@GetMapping("/loadImage")
@ResponseBody
private String loadImagefromExternalFolder(HttpServletRequest request){     
    String encodedString = "";
    
    try {       
        RandomAccessFile f =  new RandomAccessFile("C:\\your_folder_path\\your_img.PNG", "r");
        byte[] b = new byte[(int)f.length()];
        f.readFully(b);
        
        encodedString = Base64.getEncoder().encodeToString(b);

    }catch (Exception e) {
        // handle error
    }


    return encodedString;
    
}
PRTJ
  • 980
  • 1
  • 8
  • 15
0

Update for 2022: Use blobs -- you no longer need to waste time and bandwidth converting to base64.

Here is the example from https://developer.mozilla.org/en-US/docs/Web/API/Response#fetching_an_image

const image = document.querySelector('.my-image');
fetch('flowers.jpg')
.then(response => response.blob())
.then(blob => {
  const objectURL = URL.createObjectURL(blob);
  image.src = objectURL;
});
CaptainCodeman
  • 1,951
  • 2
  • 20
  • 33