more codes

This commit is contained in:
androidlover5842
2026-01-24 22:22:37 +05:30
parent 0d3472c60e
commit 6b6d84e40a
12 changed files with 614 additions and 228 deletions

View File

@@ -0,0 +1,103 @@
package com.android.trisolarisserver.component
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.time.OffsetDateTime
import java.util.UUID
import javax.imageio.ImageIO
@Component
class RoomImageStorage(
@Value("\${storage.rooms.root:/home/androidlover5842/docs/rooms}")
private val rootPath: String
) {
fun store(propertyId: UUID, roomId: UUID, file: MultipartFile): StoredRoomImage {
val contentType = file.contentType ?: ""
if (!contentType.startsWith("image/")) {
throw IllegalArgumentException("Only image files are allowed")
}
val bytes = file.bytes
val originalName = file.originalFilename ?: UUID.randomUUID().toString()
val ext = extensionFor(contentType, originalName)
val dir = Paths.get(rootPath, propertyId.toString(), roomId.toString())
Files.createDirectories(dir)
val base = UUID.randomUUID().toString() + "_" + OffsetDateTime.now().toEpochSecond()
val originalPath = dir.resolve("$base.$ext")
val originalTmp = dir.resolve("$base.$ext.tmp")
Files.write(originalTmp, bytes)
atomicMove(originalTmp, originalPath)
val image = readImage(bytes)
?: throw IllegalArgumentException("Unsupported image")
val thumb = resize(image, 320)
val thumbExt = if (ext.lowercase() == "jpg") "jpg" else "png"
val thumbPath = dir.resolve("${base}_thumb.$thumbExt")
val thumbTmp = dir.resolve("${base}_thumb.$thumbExt.tmp")
ByteArrayInputStream(render(thumb, thumbExt)).use { input ->
Files.copy(input, thumbTmp)
}
atomicMove(thumbTmp, thumbPath)
return StoredRoomImage(
originalPath = originalPath.toString(),
thumbnailPath = thumbPath.toString(),
contentType = contentType,
sizeBytes = bytes.size.toLong()
)
}
private fun readImage(bytes: ByteArray): BufferedImage? {
return ByteArrayInputStream(bytes).use { input -> ImageIO.read(input) }
}
private fun resize(input: BufferedImage, maxSize: Int): BufferedImage {
val width = input.width
val height = input.height
if (width <= maxSize && height <= maxSize) return input
val scale = if (width > height) maxSize.toDouble() / width else maxSize.toDouble() / height
val newW = (width * scale).toInt()
val newH = (height * scale).toInt()
val output = BufferedImage(newW, newH, BufferedImage.TYPE_INT_RGB)
val g = output.createGraphics()
g.drawImage(input, 0, 0, newW, newH, null)
g.dispose()
return output
}
private fun render(image: BufferedImage, format: String): ByteArray {
val out = java.io.ByteArrayOutputStream()
ImageIO.write(image, format, out)
return out.toByteArray()
}
private fun extensionFor(contentType: String, filename: String): String {
return when {
contentType.contains("png", true) -> "png"
contentType.contains("jpeg", true) || contentType.contains("jpg", true) -> "jpg"
filename.contains(".") -> filename.substringAfterLast('.').lowercase()
else -> "png"
}
}
private fun atomicMove(tmp: Path, target: Path) {
try {
Files.move(tmp, target, java.nio.file.StandardCopyOption.ATOMIC_MOVE, java.nio.file.StandardCopyOption.REPLACE_EXISTING)
} catch (_: Exception) {
Files.move(tmp, target, java.nio.file.StandardCopyOption.REPLACE_EXISTING)
}
}
}
data class StoredRoomImage(
val originalPath: String,
val thumbnailPath: String,
val contentType: String,
val sizeBytes: Long
)