mirror of
https://github.com/gotson/komga.git
synced 2025-12-20 23:45:11 +01:00
perf: page streaming performance
cache the zip or pdf document to avoid recreating it at every page access
This commit is contained in:
parent
02f61bac0a
commit
8de01a6fd7
2 changed files with 29 additions and 13 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package org.gotson.komga.infrastructure.mediacontainer
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import mu.KotlinLogging
|
||||
import org.apache.pdfbox.pdmodel.PDDocument
|
||||
import org.apache.pdfbox.pdmodel.PDPage
|
||||
|
|
@ -11,6 +12,7 @@ import org.gotson.komga.infrastructure.image.ImageAnalyzer
|
|||
import org.springframework.stereotype.Service
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.imageio.ImageIO
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
|
@ -25,6 +27,12 @@ class PdfExtractor(
|
|||
private val imageIOFormat = "jpeg"
|
||||
private val resolution = 1536F
|
||||
|
||||
private val cache = Caffeine.newBuilder()
|
||||
.maximumSize(20)
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
.removalListener { _: Path?, pdf: PDDocument?, _ -> pdf?.close() }
|
||||
.build<Path, PDDocument>()
|
||||
|
||||
override fun mediaTypes(): List<String> = listOf("application/pdf")
|
||||
|
||||
override fun getEntries(path: Path): List<MediaContainerEntry> =
|
||||
|
|
@ -37,16 +45,16 @@ class PdfExtractor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getEntryStream(path: Path, entryName: String): ByteArray =
|
||||
PDDocument.load(path.toFile()).use { pdf ->
|
||||
val pageNumber = entryName.toInt()
|
||||
val page = pdf.getPage(pageNumber)
|
||||
val image = PDFRenderer(pdf).renderImage(pageNumber, page.getScale(), ImageType.RGB)
|
||||
ByteArrayOutputStream().use { out ->
|
||||
ImageIO.write(image, imageIOFormat, out)
|
||||
out.toByteArray()
|
||||
}
|
||||
override fun getEntryStream(path: Path, entryName: String): ByteArray {
|
||||
val pdf = cache.get(path) { PDDocument.load(path.toFile()) }!!
|
||||
val pageNumber = entryName.toInt()
|
||||
val page = pdf.getPage(pageNumber)
|
||||
val image = PDFRenderer(pdf).renderImage(pageNumber, page.getScale(), ImageType.RGB)
|
||||
return ByteArrayOutputStream().use { out ->
|
||||
ImageIO.write(image, imageIOFormat, out)
|
||||
out.toByteArray()
|
||||
}
|
||||
}
|
||||
|
||||
private fun PDPage.getScale() = resolution / minOf(cropBox.width, cropBox.height)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.gotson.komga.infrastructure.mediacontainer
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import mu.KotlinLogging
|
||||
import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile
|
||||
|
|
@ -7,6 +8,7 @@ import org.gotson.komga.domain.model.MediaContainerEntry
|
|||
import org.gotson.komga.infrastructure.image.ImageAnalyzer
|
||||
import org.springframework.stereotype.Service
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
|
|
@ -16,6 +18,12 @@ class ZipExtractor(
|
|||
private val imageAnalyzer: ImageAnalyzer
|
||||
) : MediaContainerExtractor {
|
||||
|
||||
private val cache = Caffeine.newBuilder()
|
||||
.maximumSize(20)
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
.removalListener { _: Path?, zip: ZipFile?, _ -> zip?.close() }
|
||||
.build<Path, ZipFile>()
|
||||
|
||||
private val natSortComparator: Comparator<String> = CaseInsensitiveSimpleNaturalComparator.getInstance()
|
||||
|
||||
override fun mediaTypes(): List<String> = listOf("application/zip")
|
||||
|
|
@ -42,8 +50,8 @@ class ZipExtractor(
|
|||
.sortedWith(compareBy(natSortComparator) { it.name })
|
||||
}
|
||||
|
||||
override fun getEntryStream(path: Path, entryName: String): ByteArray =
|
||||
ZipFile(path.toFile()).use { zip ->
|
||||
zip.getInputStream(zip.getEntry(entryName)).use { it.readBytes() }
|
||||
}
|
||||
override fun getEntryStream(path: Path, entryName: String): ByteArray {
|
||||
val zip = cache.get(path) { ZipFile(path.toFile()) }!!
|
||||
return zip.getInputStream(zip.getEntry(entryName)).use { it.readBytes() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue