1

I'm trying to display images that their URLs comes from Flickr photo search API. I want to convert these image URLs to base64 so I can store the images in Session Storage and only call Flickr API if images do not exist in Session Storage:

export class AComponent {

    results: any[];
    base64;
    constructor(private http: HttpClient, private jsonp: Jsonp, private router: Router,
        private storage: SessionStorageService) {

        if (!sessionStorage.getItem("results")) {
       
            this.http.get('https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=378060923d01ccb122bd53491163355d&tags=jungle&per_page=5&format=json&nojsoncallback=1').subscribe(data => {

                this.results = (<RootObject>data).photos.photo.map((photo) => {

                    return {
                        // url:`https://farm${photo.farm}.staticflickr.com/${photo.server}/${photo.id}_${photo.secret}_m.jpg`,
                        base64: this.base64, // this line how can I get base64 image from the above url
                        title: photo.title
                    }

                });
                sessionStorage.setItem("results", JSON.stringify(this.results));
            });
        }
        else {

            this.results = JSON.parse(sessionStorage.getItem("results"))
        }

    }

}
Roham Rafii
  • 2,929
  • 7
  • 35
  • 49
Hamed Az
  • 11
  • 1
  • 1
  • 5
  • Does your response look like the response here http://joequery.me/code/flickr-api-image-search-python/ – Vinujan.S Aug 16 '17 at 08:57
  • This is my response: {"photos":{"page":1,"pages":287728,"perpage":2,"total":"575455","photo":[{"id":"36604279765","owner":"126248809@N03","secret":"d90f1a0b1c","server":"4391","farm":5,"title":"Jungle Waterfalls","ispublic":1,"isfriend":0,"isfamily":0},{"id":"36206903250","owner":"152084820@N03","secret":"5b9292a547","server":"4355","farm":5,"title":"Secret garden","ispublic":1,"isfriend":0,"isfamily":0}]},"stat":"ok"} – Hamed Az Aug 16 '17 at 09:19

3 Answers3

3

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:

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

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;
          // here you can save base64-image to session/localStorage
          localStorage.setItem('yourKey', this.imageToShow);
       }, false);

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

In createIamgeFromBlob()-Function you can save your base64-image to sessionStorage/localStorage by key. If the example above doesn't work, try to convert the result to string. For example: localStorage.setItem('yourKey', this.imageToShow.toString());.

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.

Gregor Doroschenko
  • 11,488
  • 5
  • 25
  • 37
  • thanks but my service returns more than one result and also I use HttpClient which is the latest angular module for making http request. – Hamed Az Aug 16 '17 at 12:16
2
loadImage(imageUrl) {
  const self = this;

  const xhr = new XMLHttpRequest()
  xhr.open("GET", imageUrl);
  xhr.responseType = "blob";
  xhr.send();
  xhr.addEventListener("load", function() {
      var reader = new FileReader();
      reader.readAsDataURL(xhr.response); 
      reader.addEventListener("loadend", function() {             
          self.base64Img = reader.result;
      });
  });
}

Link to plunker

In order to get the plunker to work you need a cors valid imaged. I've used a chrome extension.

In the sample code I am storing the result in a component variable. The encoded 64 image is in reader.result.

Answer taken from here

Cristi Todoran
  • 519
  • 3
  • 5
0

first you have to create Image url

imgUrl = `https://farm${photo.farm}.staticflickr.com/${photo.server}/${photo.id}_${photo.secret}.jpg`

ref

then get the base64 image

   function toDataURL(url, callback) {
          var xhr = new XMLHttpRequest();
          xhr.onload = function() {
            var reader = new FileReader();
            reader.onloadend = function() {
              callback(reader.result);
            }
            reader.readAsDataURL(xhr.response);
          };
          xhr.open('GET', url);
          xhr.responseType = 'blob';
          xhr.send();
        }

        toDataURL(imgUrl, function(dataUrl) {
          console.log('RESULT:', dataUrl)
        })

Final code

export class AComponent {

results: any[];
base64;
constructor(private http: HttpClient, private jsonp: Jsonp, private router: Router,
    private storage: SessionStorageService) {

    if (!sessionStorage.getItem("results")) {

        this.http.get('https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=378060923d01ccb122bd53491163355d&tags=jungle&per_page=5&format=json&nojsoncallback=1').subscribe(data => {
            let promises = (<RootObject>data).photos.photo.map((photo) => {
                return this.getBase64Photo(photo).then(base64Photo => {
                      return base64Photo;
                })
            }
            Promise.all(promises)
              .then(results => {
                this.results = results;
              })
              .catch(e => {
                console.error(e);
              })
            sessionStorage.setItem("results", JSON.stringify(this.results));
        });
    }
    else {

        this.results = JSON.parse(sessionStorage.getItem("results"))
    }

}

toDataURL(url, callback) {
      var xhr = new XMLHttpRequest();
      xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
          callback(reader.result);
        }
        reader.readAsDataURL(xhr.response);
      };
      xhr.open('GET', url);
      xhr.responseType = 'blob';
      xhr.send();
}

getBase64Photo(photo){
    return new Promise((resolve, reject) => {
        let url =`https://farm${photo.farm}.staticflickr.com/${photo.server}/${photo.id}_${photo.secret}_m.jpg`;
        let base64Data;
        this.toDataURL(url, (data)=>{
            resolve({
            base64: base64Data, // this line how can I get base64 image from the above url
            title: photo.title
            })
        })
      });
}

}
Vinujan.S
  • 1,199
  • 14
  • 27
  • thanks but this.base64 is undefined in return statement because base64 is not resolved yet in toDataURL. – Hamed Az Aug 16 '17 at 10:45
  • 1
    oh...!, I should have thought of synchronization problem. You can achieve synchronization using this timeout and checking technique as shown here https://stackoverflow.com/a/17491515/5202960 . Please let me know if you find hard to integrate it with your code. Happy to help. – Vinujan.S Aug 16 '17 at 10:58
  • @HamedAz please use this approach https://stackoverflow.com/a/33438314/5202960 . this is the best one for this scenario. – Vinujan.S Aug 16 '17 at 11:12