132 lines
3.4 KiB
JavaScript
132 lines
3.4 KiB
JavaScript
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 apiUrl = /\/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,
|
|
}
|