当Pixi使用WebGL去调用GPU渲染图像时,须要先将图像转化为GPU能够处理的版本。而可以被GPU处理的图像就叫作纹理,在pixi中使用纹理缓存来存储和引用全部纹理。经过将纹理分配给精灵,再将精灵添加到舞台上,从而显示图像。html
Pixi强大的loader
对象能够加载任何种类的图像资源,并保存在纹理缓存中。后续若是须要继续获取纹理,就不用再重复加载图像,直接从缓存中获取便可,减轻GPU内存占用。git
app.loader .add("imgs/1.jpg") .load(setup); function setup() { //This code will run when the loader has finished loading the image let sprite = new PIXI.Sprite(app.loader.resources["imgs/1.jpg"].texture); app.stage.add(spirte) }
Pixi的Texture
类型,实现了加载图像的静态方法。
static from(source: string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | PIXI.BaseTexture, options?: any, strict?: boolean): PIXI.Texture;
github
从容许的参数类型能够看出,咱们能够经过直接传入图像地址、img标签、canvas标签、video标签,将图像转化为纹理。canvas
var texture = PIXI.Texture.from("imgs/1.jpg"); var sprite = new PIXI.Sprite(PIXI.utils.TextureCache["imgs/1.jpg"]); app.stage.addChild(sprite);
根据连接加载图像,更推荐这种方式,能够捕获到图像加载失败缓存
ps:其实fromURL()
,内部调用的仍是from()
app
PIXI.Texture.fromURL(data) .then((texture) => { const spirte = new PIXI.Sprite(texture); app.stage.addChild(spirte); }) .catch((e) => { console.log("load error", e); });
var img = document.getElementById("img"); var texture = PIXI.Texture.from(img); var sprite = new PIXI.Sprite(texture) app.stage.addChild(sprite)
若是只是单纯的把svg做为一个单独的外部文件,其实只要按照上面两种转换纹理的方式,传入svg图像连接就能够实现了。可是若是这个svg是在同一个html页上的dom节点呢?这时候还能将其转为纹理吗?答案是能够的。dom
注意观察Texture.from()
的参数,能够传入图像的连接。那么base64
编码后的图像地址,按理来讲也能够。因此只要将页面上的svg节点,转化为base64
编码便可。ide
function getSvgBase64(id) { var svg = document.getElementById(id) return "data:image/svg+xml;base64," + window.btoa(svg.outerHTML); }
关键代码:window.btoa()
建立一个base64
编码的字符串,解码方法 window.atob()
。svg
首先,从Texture.from()
开始入手,咱们具体看看pixi是如何加载图像纹理的。函数
在from方法中有这么一句话texture = new Texture(new BaseTexture(source, options));
。全部的Texture
对应的还有一个BaseTexture
,他们之间的关系能够这么解释
BaseTexture : The base texture source to create the texture from
接下来看一下 BaseTexture
类的构造函数,其中调用了autoDetectResource()
方法,在这个方法中真正的对资源进行了检测分类,并根据不一样类型的资源调用不一样的资源插件(ResourcePlugin)。
function autoDetectResource(source: unknown, options?: IAutoDetectOptions): Resource { if (!source) { return null; } let extension = ''; if (typeof source === 'string') { // search for file extension: period, 3-4 chars, then ?, # or EOL const result = (/\.(\w{3,4})(?:$|\?|#)/i).exec(source); if (result) { extension = result[1].toLowerCase(); } } for (let i = INSTALLED.length - 1; i >= 0; --i) { const ResourcePlugin = INSTALLED[i]; if (ResourcePlugin.test && ResourcePlugin.test(source, extension)) { return new ResourcePlugin(source, options); } } throw new Error('Unrecognized source type to auto-detect Resource'); }
INSTALLED
在index.ts中已经初始化注入全部的ResourcePlugin
INSTALLED.push( ImageResource, ImageBitmapResource, CanvasResource, VideoResource, SVGResource, BufferResource, CubeResource, ArrayResource );
在这里能够看到,pixi中有一个SVGResource
,咱们就以这个为例继续深刻看下内部的处理机制。
简化版SVGResource
类:
export class SVGResource extends BaseImageResource { constructor(sourceBase64: string, options?: ISVGResourceOptions) { //... super(document.createElement('canvas')); if (options.autoLoad !== false) { this.load(); } } load(): Promise<SVGResource> { // Convert SVG inline string to data-uri if ((/^\<svg/).test(this.svg.trim())) { if (!btoa) { throw new Error('Your browser doesn\'t support base64 conversions.'); } (this as any).svg = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(this.svg)))}`; } this._loadSvg(); return this._load; } /** * Loads an SVG image from `imageUrl` or `data URL`. * * @private */ private _loadSvg(): void { const tempImage = new Image(); BaseImageResource.crossOrigin(tempImage, this.svg, this._crossorigin); tempImage.src = this.svg;//将base64编码的Svg字符串,建立为Image对象 tempImage.onload = (): void => { // Draw the Svg to the canvas canvas .getContext('2d') .drawImage(tempImage, 0, 0, svgWidth, svgHeight, 0, 0, width, height); }; } static test(source: unknown, extension?: string): boolean { // url file extension is SVG return extension === 'svg' // source is SVG data-uri || (typeof source === 'string' && (/^data:image\/svg\+xml(;(charset=utf8|utf8))?;base64/).test(source)) // source is SVG inline || (typeof source === 'string' && source.indexOf('<svg') === 0); } }
看完这里就差很少明白了,对于传入的Source
来讲,当在autoDetectResource()
中经过test()
方法检测到资源为SVG格式后,将其转换为Base64字符串(也就是说直接传入拼接好的svg字符串也是能够被解析的~),而后再load为Image
对象,加载到临时canvas
中。最后再经过BaseImageResource
的upload()
调用GPU输出图像资源。
一步步了解一个东西过程仍是颇有意思的,每走一步都会有新的发现。事实上仍是有不少东西没有搞懂,就留着之后去发现了。