gongxiangp2/lib/white-background-preview.ts
chenpei 4712175cb0 feat(素材链路): 发布白底图双轨与AI生图回传能力
- 完成白底图 WebP 双轨接口、上传链路与预览缓存改造
- 新增 AI 生图平台成品回传接口、任务状态与表单规则
- 补齐 AI 生成标签、任务详情补全、相关测试与对接文档
2026-03-25 10:28:02 +08:00

79 lines
2.1 KiB
TypeScript

import { existsSync } from 'fs'
import path from 'path'
import sharp from 'sharp'
import { getWhiteBackgroundPreviewRelativePathFromAssetPath } from '@/lib/standard-model-white-background'
export const WHITE_BACKGROUND_PREVIEW_MAX_DIMENSION = 1500
const WHITE_BACKGROUND_ORIGINAL_WEBP_OPTIONS = {
quality: 92,
alphaQuality: 100,
}
const WHITE_BACKGROUND_PREVIEW_WEBP_OPTIONS = {
quality: 82,
alphaQuality: 100,
}
function isHttpUrl(url?: string | null): boolean {
return /^https?:\/\//i.test(String(url || '').trim())
}
function normalizeRootRelativePath(fileUrl: string): string {
const normalized = fileUrl.trim().replace(/\\/g, '/').replace(/^\.?\//, '')
return normalized ? `/${normalized}` : ''
}
function resolveAbsoluteLocalPath(fileUrl: string): string {
const normalized = fileUrl.trim().replace(/\\/g, '/')
if (path.isAbsolute(normalized)) {
return normalized
}
return path.join(process.cwd(), normalized.replace(/^\/+/, ''))
}
export async function buildWhiteBackgroundWebpVariants(buffer: Buffer) {
const original = await sharp(buffer)
.rotate()
.webp(WHITE_BACKGROUND_ORIGINAL_WEBP_OPTIONS)
.toBuffer()
const preview = await sharp(buffer)
.rotate()
.resize({
width: WHITE_BACKGROUND_PREVIEW_MAX_DIMENSION,
height: WHITE_BACKGROUND_PREVIEW_MAX_DIMENSION,
fit: 'inside',
withoutEnlargement: true,
})
.webp(WHITE_BACKGROUND_PREVIEW_WEBP_OPTIONS)
.toBuffer()
return {
original,
preview,
}
}
export function resolveWhiteBackgroundPreviewFileUrl(fileUrl?: string | null): string | null {
const normalizedFileUrl = String(fileUrl || '').trim()
if (!normalizedFileUrl) {
return null
}
if (isHttpUrl(normalizedFileUrl)) {
return normalizedFileUrl
}
const previewRelativePath = getWhiteBackgroundPreviewRelativePathFromAssetPath(normalizedFileUrl)
if (previewRelativePath) {
const previewAbsolutePath = resolveAbsoluteLocalPath(previewRelativePath)
if (existsSync(previewAbsolutePath)) {
return normalizeRootRelativePath(previewRelativePath)
}
}
return normalizeRootRelativePath(normalizedFileUrl)
}