const { request } = require('./wx-promisify') function buildApiUrl() { const app = getApp() const apiUrl = app && app.globalData ? app.globalData.svgRenderApiUrl : '' if (!apiUrl) { throw new Error('未配置渲染 API 地址') } return apiUrl } function normalizeResult(data) { if (!data || typeof data !== 'object') { throw new Error('渲染服务返回格式无效') } if (typeof data.svg !== 'string' || !data.svg.trim()) { throw new Error('渲染服务未返回有效 SVG') } return { svg: data.svg, width: Number(data.width) || 0, height: Number(data.height) || 0, fontName: data.fontName || 'Unknown', fontId: data.fontId || '', } } function decodeArrayBuffer(buffer) { try { if (!buffer) return '' if (typeof buffer === 'string') return buffer if (typeof TextDecoder === 'function') { return new TextDecoder('utf-8').decode(buffer) } const bytes = new Uint8Array(buffer) let text = '' for (let i = 0; i < bytes.length; i += 1) { text += String.fromCharCode(bytes[i]) } return decodeURIComponent(escape(text)) } catch (error) { return '' } } async function renderSvgByApi(payload) { const app = getApp() const timeout = app && app.globalData && app.globalData.apiTimeoutMs ? Number(app.globalData.apiTimeoutMs) : 30000 const response = await request({ url: buildApiUrl(), method: 'POST', timeout, header: { 'content-type': 'application/json', }, data: { fontId: payload.fontId, text: payload.text, fontSize: payload.fontSize, fillColor: payload.fillColor, letterSpacing: payload.letterSpacing, maxCharsPerLine: payload.maxCharsPerLine, }, }) if (!response || response.statusCode < 200 || response.statusCode >= 300) { throw new Error(`渲染服务请求失败,状态码: ${response && response.statusCode}`) } const body = response.data || {} if (!body.ok) { throw new Error(body.error || '渲染服务返回错误') } return normalizeResult(body.data) } async function renderPngByApi(payload) { const app = getApp() const timeout = app && app.globalData && app.globalData.apiTimeoutMs ? Number(app.globalData.apiTimeoutMs) : 30000 const baseApiUrl = buildApiUrl() const configuredPngApiUrl = app && app.globalData ? app.globalData.pngRenderApiUrl : '' const apiUrl = configuredPngApiUrl || ( /\/api\/render-svg$/.test(baseApiUrl) ? baseApiUrl.replace(/\/api\/render-svg$/, '/api/render-png') : `${baseApiUrl.replace(/\/$/, '')}/render-png` ) const response = await request({ url: apiUrl, method: 'POST', timeout, responseType: 'arraybuffer', header: { 'content-type': 'application/json', accept: 'image/png', }, data: { fontId: payload.fontId, text: payload.text, fontSize: payload.fontSize, fillColor: payload.fillColor, letterSpacing: payload.letterSpacing, maxCharsPerLine: payload.maxCharsPerLine, }, }) if (!response || response.statusCode !== 200) { let message = `PNG 渲染服务请求失败,状态码: ${response && response.statusCode}` const maybeText = decodeArrayBuffer(response && response.data) if (maybeText && maybeText.includes('error')) { message = maybeText } throw new Error(message) } if (!(response.data instanceof ArrayBuffer)) { throw new Error('PNG 渲染服务返回格式无效') } return response.data } module.exports = { renderSvgByApi, renderPngByApi, }