繁体   English   中英

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

[英]Angular 5 how to display base64 encoded string as jpeg

我正在尝试将 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总是有一个“text/plain”类型: Blob(26544) {size: 26544, type: "text/plain"}

type 属性是只读的,所以我不能修改它。 相反,我等到 blob 通过 FileReader 的“readAsDataURL”方法转换为字符串,然后我用“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;
    }

然后修改 angular 组件以仅使用返回对象的两个属性,在此接口中定义:

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

目标是能够从 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="
    }
}

更好的方法是从服务器返回 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));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM