Files
font2pic/miniprogram/utils/mp/render-api.js
2026-02-09 16:09:44 +08:00

135 lines
3.5 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 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,
}