Angular 5如何将base64编码的字符串显示为jpeg

时间:2018-09-24 23:17:24

标签: c# angular image

我正在尝试将base64编码的字符串显示为jpeg。在服务器(C#)上,我只是返回编码的字符串(出于测试目的只是硬编码,忽略了传递的参数):

    [HttpGet("[action]")]
    public string GetImage(string imageInfo)
    {
        // get the path to the image, using the passed imageInfo
        var imgPath = @"C:\SmallFiles\TestLogo.jpg";

        // return base64 string
        byte[] imageArray = System.IO.File.ReadAllBytes(imgPath);
        string base64ImageRepresentation = Convert.ToBase64String(imageArray);
        return base64ImageRepresentation;

    }

当我采用该字符串(base64ImageRepresentation)并将其粘贴到文本到jpeg转换器(https://onlinejpgtools.com/convert-base64-to-jpg)中时,图像会正确显示,并且编码后的字符串以“ / 9j / 4”开头。而且我可以使用Chrome的“网络”标签来验证这实际上是否已返回浏览器。

现在,这是我的Angular 5组件:

@Component({
selector: 'app-home',
templateUrl: './home.component.html',
})
export class HomeComponent {
  baseUrl: string;

  sanitizedImageSrc: SafeResourceUrl;

  constructor(private route: ActivatedRoute, private _http: HttpClient, @Inject('BASE_URL') baseUrl: string, private _sanitizer: DomSanitizer) {
this.baseUrl = baseUrl;
}


ngOnInit() {
// if image information is being passed to the page, get the parameter information
let imageLookupInfo = this.route.snapshot.queryParamMap.get('imgInfo');

if (imageLookupInfo)
  this.getImage(imageLookupInfo).subscribe(
    data => {
      this.createImageFromBlob(data);
    },
    error => console.error(error));
}

createImageFromBlob(image: Blob) {
    let reader = new FileReader();

    reader.addEventListener("load", () => {
      let result = reader.result;
      let imgString = result.toString().replace('text/plain', 'image/jpeg');
      this.sanitizedImageSrc = this._sanitizer.bypassSecurityTrustResourceUrl(imgString);
    }, false);

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

getImage(imageLookupInfo: string): Observable<Blob> {
    return this._http.get(this.baseUrl + 'api/SampleData/GetImage?imageInfo=' + imageLookupInfo, { responseType: "blob" });    
  }
}

还有我的HTML:

<div class='row'>
  <div class='col-lg-10 col-md-10 col-sm-10 col-xs-10'>
    <h1>Test Image Display</h1>
    <div *ngIf="sanitizedImageSrc">
      <img  [src]="sanitizedImageSrc" width="100" height="50">
    </div>    
  </div>
</div>

在createImageFromBlob方法中,我发现图像Blob始终具有“文本/纯文本”类型: Blob(26544) {size: 26544, type: "text/plain"}

type属性是只读的,因此我无法对其进行修改。相反,我等到通过FileReader的“ readAsDataURL”方法将blob转换为字符串,然后用“ image / jpeg”替换(请告诉我是否有更好的方法),这给了我imgString这样开始:

"data:image/jpeg;base64,LzlqLzRBQVFTa1pKUmdBQkFRRUF"

请注意,数据现在如何以“ Lzlq”而不是“ / 9j / 4”开头。为什么会这样???当我复制编码数据的全文并将其粘贴到相同的text-to-jpeg转换器(https://onlinejpgtools.com/convert-base64-to-jpg)中时,我完全看不到图像,这正是我的网页中显示的内容-根本没有显示所有。没有错误,只有图像。

我在做什么错?这是怎么回事看来这应该很容易。有人有一个可行的方法来做到这一点吗?

任何帮助将不胜感激。

谢谢你, -约翰

更新: 我使用base64编码的字符串来完成此工作,如下所示。 不是回答为什么Blob方法对我不起作用的问题,我仍然想知道,但是这种方法对我有用,以防万一有人觉得有用。

1)修改服务器端以返回定义如下的ImageInfo对象:

public class ImageInfo
{
    public string FileExtension { get; set; }
    public string Base64EncodedContent { get; set; }
}

所以服务器端代码现在看起来像这样:

    [HttpGet("[action]")]
    public ImageInfo GetImageInfo(string imageInfo)
    {
        // get the path to the image, using the passed imageInfo
        var imgPath = @"C:\SmallFiles\TestLogo.jpg";

        // get image as base64 string
        byte[] imageArray = System.IO.File.ReadAllBytes(imgPath);
        string base64ImageRepresentation = Convert.ToBase64String(imageArray);

        var info = new ImageInfo();
        info.FileExtension = "jpeg";
        info.Base64EncodedContent = base64ImageRepresentation;

        return info;
    }

然后将角度分量修改为仅使用此接口中定义的返回对象的两个属性:

export interface ImageInfo {
    fileExtension: string;
    base64EncodedContent: string;
}

该组件看起来像这样(只是概念证明代码-不是有价值的实现):

import { Component, Inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

import { ImageInfo } from '../interfaces/imageInfo';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
})
export class HomeComponent {
  baseUrl: string;
  sanitizedImageSrc: SafeResourceUrl;

  constructor(private route: ActivatedRoute, private _http: HttpClient, @Inject('BASE_URL') baseUrl: string, private _sanitizer: DomSanitizer) {
    this.baseUrl = baseUrl;
  }


  ngOnInit() {
    // if image information is being passed to the page, get the parameter information
    let imageLookupInfo = this.route.snapshot.queryParamMap.get('imgInfo');

    if (imageLookupInfo)
      this.getImageInfo(imageLookupInfo)
        .subscribe(
          imageInfo => {
            this.sanitizedImageSrc = this._sanitizer.bypassSecurityTrustResourceUrl('data:image/' + imageInfo.fileExtension + ';base64,' + imageInfo.base64EncodedContent);
            },
          error => console.error(error)
        );
  }

  getImageInfo(imageLookupInfo: string): Observable<ImageInfo> {
    return this._http.get<ImageInfo>(this.baseUrl + 'api/SampleData/GetImageInfo?imageInfo=' + imageLookupInfo);
  }
}

2 个答案:

答案 0 :(得分:0)

更好的方法是从服务器返回byte []并按如下方式使用

getImage(imageId: string): Observable<ImageSource> {
    return this.http.get(`${dashboardImagesUrl}/${imageId}`, { responseType: 'blob', observe: 'response' }).map((response) => {
      if (response) {
        const headers = response.headers;
        const blob = new Blob([response.body], { type: headers.get('content-type') });
        const urlCreator = window.URL;

        return {
          width: Number(response.headers.get('X-Image-Width')),
          height: Number(response.headers.get('X-Image-Height')),
          backgroundImage: this._sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob))
        };
      }
    });
  }

HTML

<img [src]="imageSource?.backgroundImage">

将图像的高度和宽度设置为来自服务器的标题

下面的服务器代码可能对您没有帮助,但对于java-spring来说,下面的人会有用

Java后端

public class ImageEntity {

    @Id
    private String id;

    private byte[] imageByteArr;

    private int height;

    private int width;

    public static ImageEntity create(MultipartFile file) {
        try {
            final BufferedImage image = ImageIO.read(file.getInputStream());
            if(image == null) {
                log.error("Can't convert the file to a buffered image.");
                throw new ImageProcessingException();
            }
            final ImageEntity entity = new ImageEntity();
            entity.setImageByteArr(file.getBytes());
            entity.setHeight(image.getHeight());
            entity.setWidth(image.getWidth());
            return entity;
        } catch (IOException exp) {
            log.error("Exception while converting image file:", exp);
            throw new ImageProcessingException(exp);
        }
    }

}

控制器

@RequestMapping(
            path = "/{id}",
            method = RequestMethod.GET,
            produces = { MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE })
    public ResponseEntity<byte[]> get(@PathVariable String id) {
        final ImageEntity entity = this.repository.findById(id).get(); // i'm reading from mongodb
        final HttpHeaders headers = new HttpHeaders();
        headers.setCacheControl(CacheControl.noCache().getHeaderValue());
        headers.set(X_IMAGE_WIDTH_HEARDER, String.valueOf(entity.getWidth()));
        headers.set(X_IMAGE_HEIGHT_HEADER, String.valueOf(entity.getHeight()));
        return new ResponseEntity<>(entity.getImageByteArr(), headers, HttpStatus.OK);
    }

保存时只需使用

this.repository.save(ImageEntity.create(file));

答案 1 :(得分:0)

目标是能够从JSON对象获取Base64图像并显示该图像。图像通常以Base64编码存储在数据库中,并且REST服务用于访问数据库以将数据返回到Web应用程序。本示例中使用的JSON对象模拟了REST API可能提供的有效负载类型。

这是在Angular 9中创建的:

app.module-您的模块将不一样,HttpClientModule导入是此处的重要部分。

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ImageComponent } from './image/image.component';

@NgModule({
  declarations: [
    AppComponent,
    ImageComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html-只是粘贴演示的地方

<app-image></app-image>

image-model.ts-一个简单的数据模型,请注意SafeResourceUrl导入:

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

export class ImageRecord {
    
    public _name: string;
    public _imgUrlSafe: SafeResourceUrl;

    constructor(name: string,
                imgUrlSafe?: SafeResourceUrl)
    {
        this._name = name;
        if (imgUrlSafe)
        {
            this._imgUrlSafe = imgUrlSafe;
        }
        else
        {
            this._imgUrlSafe = null;
        }
        

    }
}

image.service.ts-一个简单的服务,使用HttpClient来获取JSON,就好像您在进行真正的服务调用一样。请注意,使用DomSanitizer.bypassSecurityTrustUrl()格式化Base64图像数据,以便可以正确呈现它。

import { Injectable} from '@angular/core';
import { ImageRecord} from './image-model';
import { HttpClient} from '@angular/common/http';
import { tap } from 'rxjs/operators';
import { DomSanitizer } from '@angular/platform-browser';

@Injectable({
  providedIn: 'root'
})
export class ImageService {

private _imageRecord: ImageRecord;

constructor(private _httpClient: HttpClient,
            private _domSanitizer: DomSanitizer) { }
  
public sendGetRequestNoHeaders(getUrl: string){
  return this._httpClient.get(getUrl, {observe: 'response'});
}
   
loadImageRecordsFromJson()
{
  console.log("loadImageRecordsFromJson");

  return this.sendGetRequestNoHeaders('../../../assets/image.json').pipe(tap(
  (response => 
    {

      console.log("response.body: " + response.body);

      this._imageRecord = new ImageRecord(response.body['myimage'].name,
                                          this._domSanitizer.bypassSecurityTrustUrl('data:image/jpeg;base64,' +  response.body['myimage'].ImgBase64)
      );
    }
  )));
}


getImage()
{
  return this._imageRecord;
}

}

image.component.ts-从服务获取记录。

import { Component, OnInit } from '@angular/core';
import { ImageRecord } from './image-model';
import { ImageService } from './image.service'

@Component({
  selector: 'app-image',
  templateUrl: './image.component.html',
  styleUrls: ['./image.component.css']
})
export class ImageComponent implements OnInit {

  public _imageRecord: ImageRecord;
  constructor(private _imageService: ImageService) { }

  ngOnInit(): void {
    this._imageService.loadImageRecordsFromJson().subscribe(() => {
      this._imageRecord = this._imageService.getImage();
    });
  }

}

image.component.html-显示记录。

<h1>Your Image From Base64 and JSON</h1>

<ng-container *ngIf="_imageRecord">
    <div class="float-left">
        <h4 class="list-group-item-heading">{{_imageRecord._name}}</h4>
    </div>

    <span class="float-right">
    <img [src]="_imageRecord._imgUrlSafe"          
    alt="where is my image?" 
    class="img-responsive" 
    style="max-height: 40px; max-width: 40px;"
    >
    </span>
</ng-container>

src / assets / image.json-带有名称和Base64图像的单个记录。

{
    "myimage":
    {
        "name": "One",
        "ImgBase64":"/9j/4AAQSkZJRgABAQEASABIAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAoACgDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAYFAv/EABkBAQADAQEAAAAAAAAAAAAAAAAEBQYBCP/aAAwDAQACEAMQAAABk8j6FAAAAHPeS0/J1dfrQBkSafXjXAAAA//EABwQAAEDBQAAAAAAAAAAAAAAAAQDETABAgUTIP/aAAgBAQABBQKKrttMQyHBIl6x0H//xAAhEQABAwMEAwAAAAAAAAAAAAABAwQRAiEwAAUTUSAxgf/aAAgBAwEBPwHEZi2ubcEHyCS6gIrmwHQ79+Llmos8QcUm1Ez9w//EABsRAAICAwEAAAAAAAAAAAAAAAIDATASIDFR/9oACAECAQE/Aa8VEopGOagyBWQe0//EAB4QAAEDBAMAAAAAAAAAAAAAAAIBAxEEEiEwACAx/9oACAEBAAY/AtWPeUrbrwkLsyIDjrSvIqWtXTOn/8QAHBAAAwABBQAAAAAAAAAAAAAAAREhMAAgMUFR/9oACAEBAAE/IcVsRHxozTqoBD03aE9kkWWOsP8A/9oADAMBAAIAAwAAABBttttuBtsNttt//8QAHhEBAAIBBAMAAAAAAAAAAAAAAREhMQAgMEFRYXH/2gAIAQMBAT8Q4rnfqcT702RnGBZlKt8mNpuCuZlhBFJ9lOH/xAAcEQACAgIDAAAAAAAAAAAAAAABESEwAFEgMYH/2gAIAQIBAT8QqCc428FJJ2ddcTSEovKf/8QAHBABAQABBQEAAAAAAAAAAAAAARFhACEwMUEg/9oACAEBAAE/EOLI1neXGk9LOpchK3T06+WQzGJYQCPW9Th//9k="
    }
}