gongxiangp2/lib/psd-processor.ts
chenpei e69f15337d feat: Add automatic PSD preview generation
- Add psd-processor library to auto-generate previews from PSD files
- Update upload API to detect PSD files and generate previews automatically
- Make preview image optional for PSD file uploads
- Update UploadModal UI to show PSD files don't require manual preview upload
- Install ag-psd package for PSD processing
2025-10-26 15:49:33 +08:00

128 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { readPsd } from 'ag-psd'
import sharp from 'sharp'
import fs from 'fs/promises'
interface PsdProcessResult {
success: boolean
previewPath?: string
width?: number
height?: number
error?: string
}
/**
* 从PSD文件生成预览图
* @param psdFilePath PSD文件路径
* @param outputPath 输出预览图路径
* @param maxSize 最大尺寸(宽或高),默认800px
* @returns 处理结果
*/
export async function generatePsdPreview(
psdFilePath: string,
outputPath: string,
maxSize: number = 800
): Promise<PsdProcessResult> {
try {
// 读取PSD文件
const psdBuffer = await fs.readFile(psdFilePath)
// 解析PSD
const psd = readPsd(psdBuffer, {
skipLayerImageData: true, // 跳过图层数据,只读取合成图像
skipThumbnail: false
})
if (!psd) {
return {
success: false,
error: 'Failed to parse PSD file'
}
}
// 获取PSD的宽高
const width = psd.width || 0
const height = psd.height || 0
if (width === 0 || height === 0) {
return {
success: false,
error: 'Invalid PSD dimensions'
}
}
// 如果PSD有缩略图,优先使用缩略图
if (psd.imageData) {
const imageData = psd.imageData
const channels = 4 // RGBA
// 将PSD图像数据转换为Buffer
const rawBuffer = Buffer.from(imageData.data)
// 使用Sharp处理图像
await sharp(rawBuffer, {
raw: {
width: imageData.width,
height: imageData.height,
channels: channels
}
})
.resize(maxSize, maxSize, {
fit: 'inside',
withoutEnlargement: true
})
.jpeg({
quality: 90,
mozjpeg: true
})
.toFile(outputPath)
return {
success: true,
previewPath: outputPath,
width,
height
}
}
return {
success: false,
error: 'No image data found in PSD file'
}
} catch (error) {
console.error('Error generating PSD preview:', error)
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
}
}
}
/**
* 检查文件是否为PSD格式
* @param filePath 文件路径
* @returns 是否为PSD文件
*/
export async function isPsdFile(filePath: string): Promise<boolean> {
try {
const buffer = await fs.readFile(filePath, { encoding: null })
// PSD文件签名:8BPS
return buffer.length > 4 &&
buffer[0] === 0x38 && // '8'
buffer[1] === 0x42 && // 'B'
buffer[2] === 0x50 && // 'P'
buffer[3] === 0x53 // 'S'
} catch {
return false
}
}
/**
* 从文件扩展名判断是否为PSD
* @param filename 文件名
* @returns 是否为PSD文件
*/
export function hasPsdExtension(filename: string): boolean {
return filename.toLowerCase().endsWith('.psd')
}