feat(chat-character-image): 캐릭터 이미지

- 등록시 블러 이미지를 생성하여 저장하는 기능 추가
This commit is contained in:
2025-08-21 04:00:02 +09:00
parent dd6849b840
commit 2a30b28e43
4 changed files with 155 additions and 7 deletions

View File

@@ -35,7 +35,10 @@ class AdminCharacterImageController(
private val imageCloudFront: ImageContentCloudFront,
@Value("\${cloud.aws.s3.content-bucket}")
private val s3Bucket: String
private val s3Bucket: String,
@Value("\${cloud.aws.s3.bucket}")
private val freeBucket: String
) {
@GetMapping("/list")
@@ -65,13 +68,19 @@ class AdminCharacterImageController(
val objectMapper = ObjectMapper()
val request = objectMapper.readValue(requestString, RegisterCharacterImageRequest::class.java)
// 1) 임시 경로로 엔티티 생성하기 전에 파일 업로드 경로 계산
val tempKey = buildS3Key(characterId = request.characterId)
val imagePath = saveImage(tempKey, image)
// 업로드 키 생성
val s3Key = buildS3Key(characterId = request.characterId)
// 원본 저장 (content-bucket)
val imagePath = saveImageToBucket(s3Key, image, s3Bucket)
// 블러 생성 및 저장 (무료 이미지 버킷)
val blurImagePath = saveBlurImageToBucket(s3Key, image, freeBucket)
imageService.registerImage(
characterId = request.characterId,
imagePath = imagePath,
blurImagePath = blurImagePath,
price = request.price,
isAdult = request.isAdult,
triggers = request.triggers ?: emptyList()
@@ -108,13 +117,13 @@ class AdminCharacterImageController(
return "characters/$characterId/images/$fileName"
}
private fun saveImage(filePath: String, image: MultipartFile): String {
private fun saveImageToBucket(filePath: String, image: MultipartFile, bucket: String): String {
try {
val metadata = ObjectMetadata()
metadata.contentLength = image.size
return s3Uploader.upload(
inputStream = image.inputStream,
bucket = s3Bucket,
bucket = bucket,
filePath = filePath,
metadata = metadata
)
@@ -122,4 +131,36 @@ class AdminCharacterImageController(
throw SodaException("이미지 저장에 실패했습니다: ${e.message}")
}
}
private fun saveBlurImageToBucket(filePath: String, image: MultipartFile, bucket: String): String {
try {
// 멀티파트를 BufferedImage로 읽기
val bytes = image.bytes
val bimg = javax.imageio.ImageIO.read(java.io.ByteArrayInputStream(bytes))
?: throw SodaException("이미지 포맷을 인식할 수 없습니다.")
val blurred = kr.co.vividnext.sodalive.utils.ImageBlurUtil.blur(bimg, 12)
// PNG로 저장(알파 유지), JPEG 업로드가 필요하면 포맷 변경 가능
val baos = java.io.ByteArrayOutputStream()
val format = when (image.contentType?.lowercase()) {
"image/png" -> "png"
else -> "jpg"
}
javax.imageio.ImageIO.write(blurred, format, baos)
val inputStream = java.io.ByteArrayInputStream(baos.toByteArray())
val metadata = ObjectMetadata()
metadata.contentLength = baos.size().toLong()
metadata.contentType = image.contentType ?: if (format == "png") "image/png" else "image/jpeg"
return s3Uploader.upload(
inputStream = inputStream,
bucket = bucket,
filePath = filePath,
metadata = metadata
)
} catch (e: Exception) {
throw SodaException("블러 이미지 저장에 실패했습니다: ${e.message}")
}
}
}