/* * Tencent is pleased to support the open source community by making vap available. * * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the MIT License (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://opensource.org/licenses/MIT * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions and * limitations under the License. */ export default class FrameParser { constructor(source, headData) { this.config = source || {}; this.headData = headData; this.frame = []; this.textureMap = {}; } public config; private headData; private frame; public textureMap; private canvas: HTMLCanvasElement; private ctx: CanvasRenderingContext2D | null; public srcData; async init() { // 判断是url还是json对象 if (/\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]\.json/.test(this.config)) { this.config = await this.getConfigBySrc(this.config); } await this.parseSrc(this.config); this.frame = this.config.frame || []; return this; } initCanvas() { if (!this.canvas) { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.style.display = 'none'; document.body.appendChild(canvas); this.ctx = ctx; this.canvas = canvas; } } loadImg(url: string) { return new Promise((resolve, reject) => { // console.log('load img:', url) const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = function () { resolve(this); }; img.onerror = function (e) { console.error('frame 资源加载失败:' + url); reject(new Error('frame 资源加载失败:' + url)); }; img.src = url; }); } parseSrc(dataJson) { const src = (this.srcData = {}); return Promise.all( (dataJson.src || []).map(async (item) => { item.img = null; if (!this.headData[item.srcTag.slice(1, item.srcTag.length - 1)] && !this.headData[item.srcTag]) { console.warn(`vap: 融合信息没有传入:${item.srcTag}`); } else { if (item.srcType === 'txt') { if (this.headData['fontStyle'] && !item['fontStyle']) { item['fontStyle'] = this.headData['fontStyle']; } item.textStr = this.headData[item.srcTag] || item.srcTag.replace(/\[(.*)\]/, ($0, $1) => { return this.headData[$1]; }); this.initCanvas(); item.img = this.makeTextImg(item); } else if (item.srcType === 'img') { item.imgUrl = this.headData[item.srcTag] || item.srcTag.replace(/\[(.*)\]/, ($0, $1) => { return this.headData[$1]; }); try { item.img = await this.loadImg(item.imgUrl); } catch (e) {} } if (item.img) { src[item.srcId] = item; } } }) ).then(() => { if (this.canvas) { this.canvas.parentNode.removeChild(this.canvas); } }); } /** * 下载json文件 * @param jsonUrl json外链 * @returns {Promise} */ getConfigBySrc(jsonUrl: string) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', jsonUrl, true); xhr.responseType = 'json'; xhr.onload = function () { if (xhr.status === 200 || (xhr.status === 304 && xhr.response)) { const res = xhr.response; resolve(res); } else { reject(new Error('http response invalid' + xhr.status)); } }; xhr.send(); }); } /** * 文字转换图片 * @param item */ makeTextImg(item) { const { textStr, w, h, color, style, fontStyle } = item; const ctx = this.ctx; ctx.canvas.width = w; ctx.canvas.height = h; ctx.textBaseline = 'middle'; ctx.textAlign = 'center'; const getFontStyle = function () { const fontSize = Math.min(w / textStr.length, h - 8); // 需留一定间隙 const font = [`${fontSize}px`, 'Arial']; if (style === 'b') { font.unshift('bold'); } return font.join(' '); }; if (!fontStyle) { ctx.font = getFontStyle(); ctx.fillStyle = color; } else if (typeof fontStyle == 'string') { ctx.font = fontStyle; ctx.fillStyle = color; } else if (typeof fontStyle == 'object') { ctx.font = fontStyle['font'] || getFontStyle(); ctx.fillStyle = fontStyle['color'] || color; } else if (typeof fontStyle == 'function') { ctx.font = getFontStyle(); ctx.fillStyle = color; fontStyle.call(null, ctx, item); } ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.fillText(textStr, w / 2, h / 2); // console.log('frame : ' + textStr, ctx.canvas.toDataURL('image/png')) return ctx.getImageData(0, 0, w, h); } getFrame(frame) { return this.frame.find((item) => { return item.i === frame; }); } }