77

I am new to development using Angular 4. I am facing an issue while getting a response from API about displaying an image. In the API, an image file has an input-stream file. I don't know how to retrieve it and display it properly.

Can you anyone resolve it?

I tried this:

  • Image.Component.ts:

     this.http.get('http://localhost:8080/xxx/download/file/596fba76ed18aa54e4f80769')
              .subscribe((response) => { var blob = new Blob([response.text()], {type: "image/png"});
                console.log(blob);
                console.log(window.btoa(blob.toString()));           
     });
    

Results in this => W29iamVjdCBCbG9iXQ== , but it is not the correct format

and tried this also:

this.http.get('http://localhost:8080/xxx/download/file/596fba76ed18aa54e4f80769').map(Image=>Image.text())
  .subscribe(data => {
    console.log((data.toString()));   
});

Which has this result =>

 ����\ExifII*��7                                                      ��DuckyK��fhttp://ns.adobe.com/xap/1.0/<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27        "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmpMM:OriginalDocumentID="xmp.did:0280117407206811A2188F30B3BD015B" xmpMM:DocumentID="xmp.did:E2C71E85399511E7A5719C5BBD3DDB73" xmpMM:InstanceID="xmp.iid:E2C71E84399511E7A5719C5BBD3DDB73" xmp:CreatorTool="Adobe Photoshop CC 2014 (Windows)"> <xmpMM:DerivedFrom stRef:instanceID="xmp.iid:7092a9cd-b3fd-bb49-b53c-9b6e1aa1ac93" stRef:documentID="adobe:docid:photoshop:40615934-3680-11e7-911d-f07c687d49b8"/> <dc:rights> <rdf:Alt> <rdf:li xml:lang="x-default">                                                      </rdf:li> </rdf:Alt> </dc:rights> <dc:creator> <rdf:Seq/> </dc:creator> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?>���Photoshop 3.08BIMJZ%Gt6                                                      8BIM%�<".}��νz��܌��Adobed����  

but I used to encode using window.btoa, it should be error like not latin range.

Jasperan
  • 2,154
  • 1
  • 16
  • 40
Karthic G
  • 1,162
  • 1
  • 14
  • 31
  • Check out [this post](https://stackoverflow.com/questions/36443172/extracting-image-data-from-response-angular2) – Andrei Matracaru Aug 06 '17 at 10:32
  • 2
    I tried that link but it shows as " unsafe:blob:http://localhost:4200/47c05912-5beb-41bf-a791-ca8f0d86f6af net::ERR_UNKNOWN_URL_SCHEME" and that uri has direct image – Karthic G Aug 06 '17 at 13:41
  • 1
    @KarthicG If you're using Angular, you may get that error. Use `DomSanitizer.bypassSecurityTrustUrl` to fix it. – Jeppe Jun 17 '20 at 18:45

3 Answers3

202

You should set responseType: ResponseContentType.Blob in your GET-Request settings, because so you can get your image as blob and convert it later da base64-encoded source. You code above is not good. If you would like to do this correctly, then create separate service to get images from API. Beacuse it ism't good to call HTTP-Request in components.

Here is an working example:

Create image.service.ts and put following code:

Angular 4:

getImage(imageUrl: string): Observable<File> {
    return this.http
        .get(imageUrl, { responseType: ResponseContentType.Blob })
        .map((res: Response) => res.blob());
}

Angular 5+:

getImage(imageUrl: string): Observable<Blob> {
  return this.httpClient.get(imageUrl, { responseType: 'blob' });
}

Important: Since Angular 5+ you should use the new HttpClient.

The new HttpClient returns JSON by default. If you need other response type, so you can specify that by setting responseType: 'blob'. Read more about that here.

Now you need to create some function in your image.component.ts to get image and show it in html.

For creating an image from Blob you need to use JavaScript's FileReader. Here is function which creates new FileReader and listen to FileReader's load-Event. As result this function returns base64-encoded image, which you can use in img src-attribute:

imageToShow: any;

createImageFromBlob(image: Blob) {
   let reader = new FileReader();
   reader.addEventListener("load", () => {
      this.imageToShow = reader.result;
   }, false);

   if (image) {
      reader.readAsDataURL(image);
   }
}

Now you should use your created ImageService to get image from api. You should to subscribe to data and give this data to createImageFromBlob-function. Here is an example function:

getImageFromService() {
      this.isImageLoading = true;
      this.imageService.getImage(yourImageUrl).subscribe(data => {
        this.createImageFromBlob(data);
        this.isImageLoading = false;
      }, error => {
        this.isImageLoading = false;
        console.log(error);
      });
}

Now you can use your imageToShow-variable in HTML template like this:

<img [src]="imageToShow"
     alt="Place image title"
     *ngIf="!isImageLoading; else noImageFound">
<ng-template #noImageFound>
     <img src="fallbackImage.png" alt="Fallbackimage">
</ng-template>

I hope this description is clear to understand and you can use it in your project.

See the working example for Angular 5+ here.

Gregor Doroschenko
  • 11,488
  • 5
  • 25
  • 37
  • @malkoto1 I know, because I doesn't have time to update this answer. In Angular 5 you should use HttpClient instead of Http. – Gregor Doroschenko May 01 '18 at 10:34
  • 3
    Well, I have made it to work with HttpClient, but somehow it tries to parse JSON and is giving the following error: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data. I will be thankful if you have some time to update it in th enear future :) – malkoto1 May 01 '18 at 10:43
  • 1
    I have to pass headers as well. So my call is : return this httpClient.get('url', {headers: this.httpHeaders}); So, how should I pass {response-type:'blob'} ? – Rahul Sharma Sep 25 '18 at 20:33
  • @RahulSharma You can do it so: ``return this httpClient.get('url', {headers: this.httpHeaders, responseType: 'blob' });`` – Gregor Doroschenko Sep 25 '18 at 20:43
  • Shouldn't the isImageLoading variable be set to false in the reader load listener? – Daniel Jan 07 '19 at 18:50
  • I'm getting a `Maximum call stack size exceeded` error in the ` – Davide Quaglio Jun 20 '19 at 14:40
  • @ Gregor Doroschenko: Any clues on How to handle error for response Type blob in HttpRequest – Techiemanu Nov 21 '20 at 18:44
16

angular 5 :

 getImage(id: string): Observable<Blob> {
    return this.httpClient.get('http://myip/image/'+id, {responseType: "blob"});
}
  • I have to pass headers as well. So my call is : return this httpClient.get('url', {headers: this.httpHeaders}); So, how should I pass {response-type:'blob'} ? – Rahul Sharma Sep 25 '18 at 20:33
  • 2
    `{ headers: this.httpHeaders, responseType: 'blob' }` – tom Dec 24 '18 at 00:15
0

There is no need to use angular http, you can get with js native functions

// you will ned this function to fetch the image blob.
async function getImage(url, fileName) {
     // on the first then you will return blob from response
    return await fetch(url).then(r => r.blob())
    .then((blob) => { // on the second, you just create a file from that blob, getting the type and name that intend to inform
         
        return new File([blob], fileName+'.'+   blob.type.split('/')[1]) ;
    });
}

// example url
var url = 'https://img.freepik.com/vetores-gratis/icone-realista-quebrado-vidro-fosco_1284-12125.jpg';

// calling the function
getImage(url, 'your-name-image').then(function(file) {

    // with file reader you will transform the file in a data url file;
    var reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onloadend = () => {
    
    // just putting the data url to img element
        document.querySelector('#image').src = reader.result ;
    }
})
<img src="" id="image"/>
Vitor Kevin
  • 785
  • 7
  • 16