mirror of
https://github.com/gotson/komga.git
synced 2025-12-27 19:04:28 +01:00
simplify image conversion, return errors when formats (read or write) is not supported
added @Throws for checked exceptions
This commit is contained in:
parent
4c9163a535
commit
9dcaf94406
6 changed files with 53 additions and 54 deletions
|
|
@ -0,0 +1,4 @@
|
|||
package org.gotson.komga.domain.model
|
||||
|
||||
class MetadataNotReadyException : Exception()
|
||||
class UnsupportedMediaTypeException(msg: String, val mediaType: String) : Exception(msg)
|
||||
|
|
@ -6,12 +6,10 @@ import org.gotson.komga.domain.model.Book
|
|||
import org.gotson.komga.domain.model.BookMetadata
|
||||
import org.gotson.komga.domain.model.BookPageContent
|
||||
import org.gotson.komga.domain.model.Status
|
||||
import org.gotson.komga.domain.model.UnsupportedMediaTypeException
|
||||
import org.gotson.komga.domain.persistence.BookRepository
|
||||
import org.gotson.komga.infrastructure.image.ImageConverter
|
||||
import org.gotson.komga.infrastructure.image.ImageType
|
||||
import org.gotson.komga.infrastructure.image.mediaTypeToImageIOFormat
|
||||
import org.gotson.komga.infrastructure.image.toImageIOFormat
|
||||
import org.gotson.komga.infrastructure.image.toMediaType
|
||||
import org.springframework.scheduling.annotation.Async
|
||||
import org.springframework.scheduling.annotation.AsyncResult
|
||||
import org.springframework.stereotype.Service
|
||||
|
|
@ -61,28 +59,32 @@ class BookManager(
|
|||
}.also { logger.info { "Thumbnail generated in ${DurationFormatUtils.formatDurationHMS(it)}" } })
|
||||
}
|
||||
|
||||
fun getBookPage(book: Book, number: Int, convertTo: ImageType = ImageType.ORIGINAL): BookPageContent {
|
||||
@Throws(UnsupportedMediaTypeException::class)
|
||||
fun getBookPage(book: Book, number: Int, convertTo: ImageType? = null): BookPageContent {
|
||||
val pageContent = bookParser.getPageContent(book, number)
|
||||
val pageMediaType = book.metadata.pages[number - 1].mediaType
|
||||
|
||||
if (convertTo != ImageType.ORIGINAL) {
|
||||
val pageFormat = mediaTypeToImageIOFormat(pageMediaType)
|
||||
val convertFormat = convertTo.toImageIOFormat()
|
||||
if (pageFormat != null && convertFormat != null && imageConverter.canConvert(pageFormat, convertFormat)) {
|
||||
if (pageFormat != convertFormat) {
|
||||
try {
|
||||
logger.info { "Trying to convert page #$number of book $book from $pageFormat to $convertFormat" }
|
||||
val convertedPage = imageConverter.convertImage(pageContent, convertFormat)
|
||||
return BookPageContent(number, convertedPage, convertTo.toMediaType() ?: "application/octet-stream")
|
||||
} catch (ex: Exception) {
|
||||
logger.error(ex) { "Failed to convert page #$number of book $book to $convertFormat" }
|
||||
}
|
||||
} else {
|
||||
logger.warn { "Cannot convert page #$number of book $book from $pageFormat to $convertFormat: same format" }
|
||||
}
|
||||
} else {
|
||||
logger.warn { "Cannot convert page #$number of book $book to $convertFormat: unsupported format" }
|
||||
convertTo?.let {
|
||||
val msg = "Convert page #$number of book $book from $pageMediaType to ${it.mediaType}"
|
||||
if (!imageConverter.supportedReadMediaTypes.contains(pageMediaType)) {
|
||||
throw UnsupportedMediaTypeException("$msg: unsupported read format $pageMediaType", pageMediaType)
|
||||
}
|
||||
if (!imageConverter.supportedWriteMediaTypes.contains(it.mediaType)) {
|
||||
throw UnsupportedMediaTypeException("$msg: unsupported cannot write format ${it.mediaType}", it.mediaType)
|
||||
}
|
||||
if (pageMediaType == it.mediaType) {
|
||||
logger.warn { "$msg: same format, no need for conversion" }
|
||||
return@let
|
||||
}
|
||||
|
||||
logger.info { msg }
|
||||
val convertedPage = try {
|
||||
imageConverter.convertImage(pageContent, it.imageIOFormat)
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "$msg: conversion failed" }
|
||||
throw e
|
||||
}
|
||||
return BookPageContent(number, convertedPage, it.mediaType)
|
||||
}
|
||||
|
||||
return BookPageContent(number, pageContent, pageMediaType)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import net.coobird.thumbnailator.Thumbnails
|
|||
import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator
|
||||
import org.gotson.komga.domain.model.Book
|
||||
import org.gotson.komga.domain.model.BookMetadata
|
||||
import org.gotson.komga.domain.model.MetadataNotReadyException
|
||||
import org.gotson.komga.domain.model.Status
|
||||
import org.gotson.komga.domain.model.UnsupportedMediaTypeException
|
||||
import org.gotson.komga.domain.model.path
|
||||
import org.gotson.komga.infrastructure.archive.ContentDetector
|
||||
import org.gotson.komga.infrastructure.archive.PdfExtractor
|
||||
|
|
@ -36,6 +38,7 @@ class BookParser(
|
|||
private val thumbnailSize = 300
|
||||
private val thumbnailFormat = "png"
|
||||
|
||||
@Throws(UnsupportedMediaTypeException::class)
|
||||
fun parse(book: Book): BookMetadata {
|
||||
logger.info { "Trying to parse book: $book" }
|
||||
|
||||
|
|
@ -54,6 +57,7 @@ class BookParser(
|
|||
return BookMetadata(mediaType = mediaType, status = Status.READY, pages = pages, thumbnail = thumbnail)
|
||||
}
|
||||
|
||||
@Throws(MetadataNotReadyException::class)
|
||||
fun regenerateThumbnail(book: Book): BookMetadata {
|
||||
logger.info { "Regenerate thumbnail for book: $book" }
|
||||
|
||||
|
|
@ -88,6 +92,7 @@ class BookParser(
|
|||
null
|
||||
}
|
||||
|
||||
@Throws(MetadataNotReadyException::class)
|
||||
fun getPageContent(book: Book, number: Int): ByteArray {
|
||||
logger.info { "Get page #$number for book: $book" }
|
||||
|
||||
|
|
@ -98,12 +103,9 @@ class BookParser(
|
|||
|
||||
if (number > book.metadata.pages.size || number <= 0) {
|
||||
logger.error { "Page number #$number is out of bounds. Book has ${book.metadata.pages.size} pages" }
|
||||
throw ArrayIndexOutOfBoundsException("Page $number does not exist")
|
||||
throw IndexOutOfBoundsException("Page $number does not exist")
|
||||
}
|
||||
|
||||
return supportedMediaTypes.getValue(book.metadata.mediaType!!).getPageStream(book.path(), book.metadata.pages[number - 1].fileName)
|
||||
}
|
||||
}
|
||||
|
||||
class MetadataNotReadyException : Exception()
|
||||
class UnsupportedMediaTypeException(msg: String, val mediaType: String) : Exception(msg)
|
||||
|
|
@ -11,16 +11,17 @@ private val logger = KotlinLogging.logger {}
|
|||
class ImageConverter {
|
||||
|
||||
val supportedReadFormats = ImageIO.getReaderFormatNames().toList()
|
||||
val supportedReadMediaTypes = ImageIO.getReaderMIMETypes().toList()
|
||||
val supportedWriteFormats = ImageIO.getWriterFormatNames().toList()
|
||||
val supportedWriteMediaTypes = ImageIO.getWriterMIMETypes().toList()
|
||||
|
||||
init {
|
||||
logger.info { "Supported read formats: $supportedReadFormats" }
|
||||
logger.info { "Supported read mediaTypes: $supportedReadMediaTypes" }
|
||||
logger.info { "Supported write formats: $supportedWriteFormats" }
|
||||
logger.info { "Supported write mediaTypes: $supportedWriteMediaTypes" }
|
||||
}
|
||||
|
||||
fun canConvert(from: String, to: String) =
|
||||
supportedReadFormats.contains(from) && supportedWriteFormats.contains(to)
|
||||
|
||||
fun convertImage(imageBytes: ByteArray, format: String): ByteArray =
|
||||
ByteArrayOutputStream().use {
|
||||
val image = ImageIO.read(imageBytes.inputStream())
|
||||
|
|
@ -28,9 +29,3 @@ class ImageConverter {
|
|||
it.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
fun mediaTypeToImageIOFormat(mediaType: String): String? =
|
||||
if (mediaType.startsWith("image/", ignoreCase = true))
|
||||
mediaType.toLowerCase().substringAfter("/")
|
||||
else
|
||||
null
|
||||
|
|
@ -1,19 +1,6 @@
|
|||
package org.gotson.komga.infrastructure.image
|
||||
|
||||
enum class ImageType {
|
||||
ORIGINAL, PNG, JPEG
|
||||
enum class ImageType(val mediaType: String, val imageIOFormat: String) {
|
||||
PNG("image/png", "png"),
|
||||
JPEG("image/jpeg", "jpeg")
|
||||
}
|
||||
|
||||
fun ImageType.toMediaType(): String? =
|
||||
when (this) {
|
||||
ImageType.ORIGINAL -> null
|
||||
ImageType.PNG -> "image/png"
|
||||
ImageType.JPEG -> "image/jpeg"
|
||||
}
|
||||
|
||||
fun ImageType.toImageIOFormat(): String? =
|
||||
when (this) {
|
||||
ImageType.ORIGINAL -> null
|
||||
ImageType.PNG -> "png"
|
||||
ImageType.JPEG -> "jpeg"
|
||||
}
|
||||
|
|
@ -5,12 +5,13 @@ import com.github.klinq.jpaspec.likeLower
|
|||
import mu.KotlinLogging
|
||||
import org.apache.commons.io.FilenameUtils
|
||||
import org.gotson.komga.domain.model.Book
|
||||
import org.gotson.komga.domain.model.MetadataNotReadyException
|
||||
import org.gotson.komga.domain.model.Serie
|
||||
import org.gotson.komga.domain.model.Status
|
||||
import org.gotson.komga.domain.model.UnsupportedMediaTypeException
|
||||
import org.gotson.komga.domain.persistence.BookRepository
|
||||
import org.gotson.komga.domain.persistence.SerieRepository
|
||||
import org.gotson.komga.domain.service.BookManager
|
||||
import org.gotson.komga.domain.service.MetadataNotReadyException
|
||||
import org.gotson.komga.infrastructure.image.ImageType
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.PageRequest
|
||||
|
|
@ -178,11 +179,19 @@ class SerieController(
|
|||
return bookRepository.findByIdOrNull((bookId))?.let { book ->
|
||||
try {
|
||||
val convertFormat = when (convertTo?.toLowerCase()) {
|
||||
"jpg", "jpeg" -> ImageType.JPEG
|
||||
"jpeg" -> ImageType.JPEG
|
||||
"png" -> ImageType.PNG
|
||||
else -> ImageType.ORIGINAL
|
||||
"", null -> null
|
||||
else -> throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid conversion format: $convertTo")
|
||||
}
|
||||
|
||||
val pageContent = try {
|
||||
bookManager.getBookPage(book, pageNumber, convertFormat)
|
||||
} catch (e: UnsupportedMediaTypeException) {
|
||||
throw ResponseStatusException(HttpStatus.BAD_REQUEST, e.message)
|
||||
} catch (e: Exception) {
|
||||
throw ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
}
|
||||
val pageContent = bookManager.getBookPage(book, pageNumber, convertFormat)
|
||||
|
||||
ResponseEntity.ok()
|
||||
.contentType(getMediaTypeOrDefault(pageContent.mediaType))
|
||||
|
|
|
|||
Loading…
Reference in a new issue