8

I'm having lots of trouble trying to get an image I'm retrieving from my Web API to display as a background-image in my Angular application.

The Web API's action that returns the image looks like this:

    /// <summary>
    /// Returns the medium image for the specified project as image/png media type.
    /// </summary>
    /// <param name="projectId"></param>
    /// <returns></returns>
    [HttpGet("{projectId:int}/image/medium")]
    [SwaggerResponse(200, typeof(byte[]))]        
    [Produces("image/png")]
    public FileContentResult GetImageMedium(int projectId)
    {            
        var res = _repository.GetProjectResource(projectId, "Medium");
        FileContentResult result = new FileContentResult(res.ByteContent, res.MediaType);            
        return result;
    }

This is currently what my Angular service method looks like (but I have tried lots of alternatives):

  getProjectImage(id: number) {
    return this._http
      .get(`${this._url}/${id}/Image/Medium`, { headers: this._auth.headers, responseType: ResponseContentType.Blob })
      .map(response => response.arrayBuffer());
  }

And this is what I'm trying to apply to the [style.background-image] of the DOM element:

return `url(${'data:image/png;base64,' + new Buffer(response)})`

As I said before, I've been trying combinations of things from things I've found around the internet, but I have an inherent misunderstanding of most of the pieces involved. What is my Web API returning me? How can I handle that client side? How do I massage the content into something appropriate for a background-image css property? I would really like to understand this much better in addition to getting this to work. All help is greatly appreciated!

Update

I also just tried to change the Web API action to return a base64 string like this:

/// <summary>
/// Returns the medium image for the specified project as image/png media type.
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
[HttpGet("{projectId:int}/image/medium")]
[SwaggerResponse(200, typeof(byte[]))]
[Produces("image/png")]
public string GetImageMedium(int projectId)
{
    var res = _repository.GetProjectResource(projectId, "Medium");
    return Convert.ToBase64String(res);
}

and handling it client side like this:

  getProjectImage(id: number) {
    return this._http
      .get(`${this._url}/${id}/Image/Medium`, { headers: this._auth.headers });
  }

and simplifying the caller of my service to provide the following to [style.background-image] of the DOM element:

return `url(${'data:image/png;base64,' + response})`

I've console.loged the response and it indeed looks like a base64 string (I think?). But the css never changes.

Update 2

My markup is currently this:

<div class="image"
     [style.background-image]="project.image | async"></div>

My component's code is currently this:

projects.map(project => {
  project.image = this._projectsService.getProjectImage(project.projectId)
    .map(response => `url('data:image/png;base64,${response['_body']}')`)
});

I've gotten to the point where if I console.log this out, copy it, and paste it into the css rules for the div in dev tools, the image shows up. I've tried running this in NgZone and the css still won't show up. Any and all help is appreciated.

Update 3

So, if I change <div class="image" [style.background-image]="project.image | async"></div> to <img [src]="project.image | async" alt="">, I get the image to appear asynchronously. The unfortunate thing about this approach is that while the request is in flight, the image error icon is visible. This error icon remains for any items that don't return an image (incomplete database)

1
  • Did you find the solution for your question. I have exactly same issue (i.e. showing the binary image (from database via REST) as background in div Commented Oct 8, 2019 at 13:10

2 Answers 2

3

To avoid displaying the error image until the actual image if loaded, change your html to this:

<img *ngIf="project.image" [src]="project.image | async" alt="">

The solution in your Update 3 will also work. However, here is another way to do it. You can set the [style] directive of the div to add the background-image. You will have to sanitize the styles when passing them to the dom.

In your component.html:

<div class="image" [style]="backgroundImageStyle"></div>

.. to remove the error image until we get the image, we add an *ngIf:

<div class="image" *ngIf="backgroundImageStyle" 
                    [style]="backgroundImageStyle">
</div>

... and in your component.ts:

// ..
import { DomSanitizer } from '@angular/platform-browser';

// Declare a variable to store the sanitized style
private backgroundImageStyle;

// Initialize the constructor
constructor(sanitizer: DomSanitizer) { 
    // You can call this whereever you want, I am doing it in constructor
    this.backgroundImageStyle = this.getBackgroundImageStyle();
}

private getBackgroundImageStyle() {        
    // sanitize the style expression
    style = `background-image: url(${project.image})`;
    this.sanitizer.bypassSecurityTrustStyle(style);
}
// ..
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your suggestion, but the *ngIf directive didn't work for me because project.image wasn't falsey. I'm not sure if this is completely correct, but the error icon remained because project.image is an observable and not falsey. I thought this would work.
You are absolutely right about having to sanitize the styling using the DomSanitizer
Actually it didn't help. This is pretty similar to the code I already had in my own attempts. But I did not mention the DomSanitizer in my question, which is something I had tried and had removed on subsequent attempts. I'm not sure what the issue is, but I'll keep you posted if I find out what the issue was.
3
+25

Why you cannot just put your link to img to background-image directly?

<div class="image"
     [style.background-image]="url('/your-url-to-img')"></div>

The browser will do your work for you.

You need to be sure that web server returns right image and headers

8 Comments

I wonder what I can do there....good idea. The image is in the database as binary data already, is there a way to get the png out of it server side? Is that worth it?
If you already have binary data, then just write it to response with appropriate headers, like image/png or image/*
I'll try tomorrow! Thanks!
i agree. everything is actually just a bunch of binary data. i would recommend you to ponder whether to get it out of the DB though, it is just a waste of computing effort to manage it as far as i see it
@MatanCo, what do you mean by "ponder whether to get it out of the DB?" Do you mean I should have all these images locally?
|

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.