我正在尝试将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);
}
}
答案 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="
}
}