Angular base64图像管道,超出最大调用堆栈大小

时间:2017-11-21 18:41:01

标签: javascript angular

我必须将Image urls转换为base64编码的字符串(因为this

import { Pipe, PipeTransform } from '@angular/core';


declare var base64;

@Pipe({
  name: 'tobase64'
})
export class Tobase64Pipe implements PipeTransform {

  transform(value: any, args?: any): any {
    var xmlHTTP = new XMLHttpRequest();
    xmlHTTP.open('GET', value, true);
    xmlHTTP.responseType = 'arraybuffer';
    xmlHTTP.onload = (e) => {
        console.log('e',e);
      var arr = new Uint8Array(e.currentTarget.response);
      var raw = String.fromCharCode.apply(null, arr);
      var b64 = base64.encode(raw);
       var dataURL = "data:image/png;base64," + b64;
      return dataURL;
    };
    xmlHTTP.send();

    return null;
  }

}

HTML

<image x="0" y="0" width="500" height="500" [attr.xlink:href]="'assets/hand.jpg' | tobase64"    mask="url(#hole)" />  

错误:

ERROR RangeError: Maximum call stack size exceeded

1 个答案:

答案 0 :(得分:2)

从管道发出HTTP请求是完全可以的。在你的情况下,你最终只会做一个。请考虑这一点:如果将src的{​​{1}}属性绑定到可以动态更改的属性,则最终会在属性更改时进行服务器调用;无论该呼叫是XHR呼叫还是对图像的简单请求,这都不是什么大问题。我对管道不太了解的唯一两件事是:

  1. 为什么使用XMLHTTPRequest而不是Angular的Http或HttpClient服务?
  2. 为什么管道返回img?看来,即使你没有得到任何错误,你仍然不会得到结果
  3. 此解决方案需要清除两个管道:一个是用于进行XHR调用的自定义管道,另一个是Angular的内置管道null。这是我们的自定义管道:

    async

    这就是你的HTML:

    import { Pipe, PipeTransform } from '@angular/core';
    import { Http, RequestOptions, Headers, ResponseContentType } from '@angular/http';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/map';
    import 'rxjs/add/operator/switchMap';
    
    @Pipe({name: 'toBase64'})
    export class ImagePipe implements PipeTransform {
      constructor(private http: Http) {}
    
      transform(url: string) {
      const headers = new Headers({'Content-Type': 'image/*'}); /* tell that XHR is going to receive an image as response, so it can be then converted to blob */
      return this.http.get(url, new RequestOptions({headers: headers, responseType: ResponseContentType.Blob})) // specify that response should be treated as blob data
      .map(response => response.blob()) // take the blob
      .switchMap(blob => {
      // return new observable which emits a base64 string when blob is converted to base64
          return Observable.create(observer => { 
            const  reader = new FileReader(); 
            reader.readAsDataURL(blob); // convert blob to base64
            reader.onloadend = function() {             
                  observer.next(reader.result); // emit the base64 string result
            }
         });
       });
      }
    }
    

    我们使用我们的管道来获取base64字符串的可观察性,并使用<image x="0" y="0" width="500" height="500" [attr.xlink:href]="('assets/hand.jpg' | toBase64) | async" mask="url(#hole)" /> 将实际发出的字符串插入async标记内。

    您需要记住的一件事是CORS:您的图像服务器应配置为接受XHR调用来运行Angular应用程序所在域的图像,同样,您必须提供绝对URL到自定义管道,否则它将向Angular应用程序的域本身发出请求。但在你的情况下,我假设你从你自己的应用程序提供图像,所以这不应该是一个问题。