Allenph
Allenph

Reputation: 2015

Applying image blob to src in Angular JS?

I have some API endpoints which provide images, but said images require authentication. I have a service (authenticatedHttp) which is an abstraction over $http and handles the authentication token management. (This is confirmed to be working, and for all intents and purposes might as well be $http)

I am receiving the response, getting a blob and creating an object URL. All of this works. I have checked the blob and can confirm it is correct.

The problem comes in when I try to apply objectUrl to src. I have tried a simplified example using a snippet I know works and no authentication. This does not work in my Angular app, but does work in vanilla JS.

I don't know much about ObjectUrl but if it makes a difference, when I inspect the empty image I see that it's src is correct, and that if I click the link created (ex. blob:https://sub.domain.dev/de4db0e0-77c8-44bc-a934-0d270ab81687) I get redirected by ui-router.

Why is this happening and how can I correct it?

app.directive('authenticatedSrc', ['authenticatedHttp', function (authenticatedHttp) {
  var directive = {
      link: link,
      restrict: 'A'
  };
  return directive;
  function link(scope, element, attrs) {
    var requestConfig = {
      cache: 'false'
    };
    authenticatedHttp.get(attrs.authenticatedSrc, requestConfig).then(function(response) {
      var objectUrl = window.URL.createObjectURL(new Blob([response.data], { type: 'image/png' }));
      attrs.$set('src', objectUrl);
    });
  }
}]);

Upvotes: 2

Views: 1685

Answers (3)

Allenph
Allenph

Reputation: 2015

@Kaiido was correct also, but it was not my main problem.

@georgeawg solved the majority of my problem, but I did not accept his answer because his implementation (using the blob directly as the source) did not work for me.

This is my final code which works.

app.directive('authenticatedSrc', ['authenticatedHttp', function (authenticatedHttp) {
  var directive = {
      link: link,
      restrict: 'A'
  };
  return directive;
  function link(scope, element, attrs) {
    var requestConfig = {
      cache: 'false',
      responseType: 'blob'
    };
    authenticatedHttp.get(attrs.authenticatedSrc, requestConfig).then(function(response) {
      var reader = new window.FileReader();
      reader.readAsDataURL(response.data);
      reader.onloadend = function() {
        attrs.$set('src', reader.result);
      };
    });
  }
}]);

Upvotes: 1

georgeawg
georgeawg

Reputation: 48968

When downloading binary information, it is important to set the responseType:

app.directive('authenticatedSrc', ['authenticatedHttp', function (authenticatedHttp) {
  var directive = {
      link: link,
      restrict: 'A'
  };
  return directive;
  function link(scope, element, attrs) {
    var requestConfig = {
      //IMPORTANT
      responseType: 'blob',
      cache: 'false'
    };
    authenticatedHttp.get(attrs.authenticatedSrc, requestConfig).then(function(response) {
      //var objectUrl = window.URL.createObjectURL(new Blob([response.data], { type: 'image/png' }));
      var blob = response.data;
      attrs.$set('src', blob);
    });
  }
}]);

Otherwise the data gets corrupted by conversion from UTF-8 to DOMstring (UTF-16).

For more information, see MDN XHR API ResponseType.

Upvotes: 1

GeeDee
GeeDee

Reputation: 11

What is the return type of response.data? Is it a base64 encoded string? Img tag can very well render base64 encoded images when provided directly in the src attribute. Moreover, please try $sce service of angularjs to trust this objectUrl as a valid Url. $sce.trustAsURL(objectUrl) while adding to src attribute. More info https://docs.angularjs.org/api/ng/service/$sce

Upvotes: 0

Related Questions