208 lines
6.6 KiB
JavaScript
208 lines
6.6 KiB
JavaScript
import { NextResponse } from 'next/server'
|
|
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { Jimp } from 'jimp'
|
|
|
|
const Bucket = process.env.AMPLIFY_BUCKET
|
|
const s3 = new S3Client({
|
|
region: process.env.AWS_REGION,
|
|
credentials: {
|
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
},
|
|
})
|
|
|
|
const checkArea = (obj) => {
|
|
const { width, height, left, top } = obj
|
|
|
|
if (left < 0 || top < 0 || width > 1600 || height > 1000) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
const cropImage = async (Key, width, height, left, top) => {
|
|
try {
|
|
// Get the image from S3
|
|
const { Body } = await s3.send(
|
|
new GetObjectCommand({
|
|
Bucket,
|
|
Key,
|
|
}),
|
|
)
|
|
|
|
const chunks = []
|
|
for await (const chunk of Body) {
|
|
chunks.push(chunk)
|
|
}
|
|
const buffer = Buffer.concat(chunks)
|
|
|
|
let image = await Jimp.read(buffer)
|
|
image.autocrop({ tolerance: 0.0002, leaveBorder: 10 })
|
|
|
|
const resizedImage = await resizeImage(image).then((result) => {
|
|
return result
|
|
})
|
|
|
|
return await resizedImage.getBuffer('image/png')
|
|
|
|
// Convert stream to buffer
|
|
// const chunks = []
|
|
// for await (const chunk of Body) {
|
|
// chunks.push(chunk)
|
|
// }
|
|
// const imageBuffer = Buffer.concat(chunks)
|
|
|
|
// const image = await Jimp.read(Body)
|
|
|
|
// if (!checkResult) {
|
|
// processedImage = await image.toBuffer()
|
|
// }
|
|
|
|
//let processedImage
|
|
// if (!checkResult) {
|
|
// processedImage = await sharp(imageBuffer).toBuffer()
|
|
// } else {
|
|
// processedImage = await sharp(imageBuffer)
|
|
// .extract({
|
|
// width: parseInt(width),
|
|
// height: parseInt(height),
|
|
// left: parseInt(left),
|
|
// top: parseInt(top),
|
|
// })
|
|
// .png()
|
|
// .toBuffer()
|
|
// }
|
|
// return processedImage
|
|
} catch (error) {
|
|
console.error('Error processing image:', error)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
//크롭된 이미지를 가지고 높이 기준 -> 너비 기준으로 비율 변경 후 이미지에 추가
|
|
const resizeImage = async (image) => {
|
|
// //이미지를 cm로 변환
|
|
let imageHeightCm = Math.round((image.bitmap.height * 2.54) / 96) //원본 이미지 센치로 변환
|
|
let imageWidthCm = Math.round((image.bitmap.width * 2.54) / 96) //원본 이미지 센치로 변환
|
|
const calcWidthRatio = 12.89 / imageHeightCm //원본 비율 계산
|
|
|
|
let convertHeightCm = Math.round(imageHeightCm * calcWidthRatio) //변환된 이미지 CM
|
|
let convertWidthCm = Math.round(imageWidthCm * calcWidthRatio) //변환된 이미지 CM
|
|
|
|
let convertHeightBitmap = Math.round((convertHeightCm * 96) / 2.54) //비트맵 사이즈로 변환
|
|
let convertWidthBitmap = Math.round((convertWidthCm * 96) / 2.54) //비트맵 사이즈로 변환
|
|
|
|
//높이 기준으로 리사이즈를 함
|
|
image.resize({ w: convertWidthBitmap, h: convertHeightBitmap, mode: Jimp.RESIZE_BILINEAR })
|
|
|
|
//높이를 기준으로 변경 후에 가로 폭이 더 넓으면 가로폭 기준으로 다시 사이즈를 조절한다
|
|
if (convertWidthCm > 35.4) {
|
|
//너비가 더 클때
|
|
imageHeightCm = Math.round((image.bitmap.height * 2.54) / 96) //높이 기준으로 리사이즈된 이미지 크기
|
|
imageWidthCm = Math.round((image.bitmap.width * 2.54) / 96) //높이 기준으로 리사이즈된 이미지 크기
|
|
|
|
const calcWidthRatio = 35.4 / imageWidthCm //리사이즈된 이미지 가로 비율 계산
|
|
|
|
convertHeightCm = Math.round(imageHeightCm * calcWidthRatio) //너비 기준 이미지 비율 계산
|
|
convertWidthCm = Math.round(imageWidthCm * calcWidthRatio) //변환된 이미지 CM
|
|
|
|
convertHeightBitmap = Math.round((convertHeightCm * 96) / 2.54) //비트맵 사이즈로 변환
|
|
convertWidthBitmap = Math.round((convertWidthCm * 96) / 2.54) //비트맵 사이즈로 변환
|
|
|
|
image.resize({ w: convertWidthBitmap, h: convertHeightBitmap, mode: Jimp.RESIZE_BILINEAR }) //이미지 리사이즈
|
|
}
|
|
|
|
//엑셀 템플릿 너비 35.4cm, 높이 12.89cm
|
|
const convertStandardWidth = Math.round((35.4 * 96) / 2.54)
|
|
const convertStandardHeight = Math.round((12.89 * 96) / 2.54)
|
|
|
|
//엑셀 템플릿 사이즈로 배경 이미지를 생성
|
|
const mixedImage = new Jimp({ width: convertStandardWidth, height: convertStandardHeight, color: 0xffffffff })
|
|
|
|
//이미지를 중앙에 배치
|
|
const x = Math.floor((mixedImage.bitmap.width - image.bitmap.width) / 2)
|
|
const y = Math.floor((mixedImage.bitmap.height - image.bitmap.height) / 2)
|
|
|
|
//이미지를 배경 이미지에 합성
|
|
mixedImage.composite(image, x, y, {
|
|
mode: Jimp.BLEND_SOURCE_OVER,
|
|
opacitySource: 1, // 원본 투명도 유지
|
|
opacityDest: 1,
|
|
})
|
|
|
|
return mixedImage
|
|
}
|
|
|
|
export async function POST(req) {
|
|
try {
|
|
const formData = await req.formData()
|
|
const file = formData.get('file')
|
|
const objectNo = formData.get('objectNo')
|
|
const planNo = formData.get('planNo')
|
|
const type = formData.get('type')
|
|
const width = formData.get('width')
|
|
const height = formData.get('height')
|
|
const left = formData.get('left')
|
|
const top = formData.get('top')
|
|
|
|
const OriginalKey = `Drawing/${uuidv4()}`
|
|
|
|
/**
|
|
* 원본 이미지를 우선 저장한다.
|
|
* 이미지 이름이 겹지는 현상을 방지하기 위해 uuid 를 사용한다.
|
|
*/
|
|
await s3.send(
|
|
new PutObjectCommand({
|
|
Bucket,
|
|
Key: OriginalKey,
|
|
Body: Buffer.from(await file.arrayBuffer()),
|
|
ContentType: 'image/png',
|
|
}),
|
|
)
|
|
|
|
/**
|
|
* 저장된 원본 이미지를 기준으로 크롭여부를 결정하여 크롭 이미지를 저장한다.
|
|
*/
|
|
const bufferImage = await cropImage(OriginalKey, width, height, left, top)
|
|
|
|
/**
|
|
* 크롭 이미지 이름을 결정한다.
|
|
*/
|
|
const Key = `Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_${type}.png`
|
|
|
|
/**
|
|
* 크롭이 완료된 이미지를 업로드한다.
|
|
*/
|
|
await s3.send(
|
|
new PutObjectCommand({
|
|
Bucket,
|
|
Key,
|
|
Body: bufferImage,
|
|
ContentType: 'image/png',
|
|
}),
|
|
)
|
|
|
|
/**
|
|
* 크롭이미지 저장이 완료되면 원본 이미지를 삭제한다.
|
|
*/
|
|
await s3.send(
|
|
new DeleteObjectCommand({
|
|
Bucket,
|
|
Key: OriginalKey,
|
|
}),
|
|
)
|
|
|
|
const result = {
|
|
filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`,
|
|
fileName: Key,
|
|
}
|
|
|
|
return NextResponse.json(result)
|
|
} catch (error) {
|
|
console.error('Error in POST:', error)
|
|
return NextResponse.json({ error: 'Failed to process and upload image' }, { status: 500 })
|
|
}
|
|
}
|