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"))
        }

    }

}

2
  • Does your response look like the response here joequery.me/code/flickr-api-image-search-python Commented Aug 16, 2017 at 8: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"} Commented Aug 16, 2017 at 9:19

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks but my service returns more than one result and also I use HttpClient which is the latest angular module for making http request.
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

2 Comments

Thanks but base64Img is undefined in return statement when I return it from constructor.
you can just declare base64Img before the constructor like base64Img:string;
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
            })
        })
      });
}

}

3 Comments

thanks but this.base64 is undefined in return statement because base64 is not resolved yet in toDataURL.
oh...!, I should have thought of synchronization problem. You can achieve synchronization using this timeout and checking technique as shown here stackoverflow.com/a/17491515/5202960 . Please let me know if you find hard to integrate it with your code. Happy to help.
@HamedAz please use this approach stackoverflow.com/a/33438314/5202960 . this is the best one for this scenario.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.