當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輸出圖像資源。
一步步瞭解一個東西過程仍是頗有意思的,每走一步都會有新的發現。事實上仍是有不少東西沒有搞懂,就留着之後去發現了。