diff --git a/README-CHANGES.xml b/README-CHANGES.xml
index 8ec58304a..18a64ddd7 100644
--- a/README-CHANGES.xml
+++ b/README-CHANGES.xml
@@ -370,7 +370,7 @@
-
+
@@ -400,13 +400,18 @@
-
+
+
+
+
+
+
diff --git a/org.thepalaceproject.android.platform b/org.thepalaceproject.android.platform
index 22fb9049e..ce68d1001 160000
--- a/org.thepalaceproject.android.platform
+++ b/org.thepalaceproject.android.platform
@@ -1 +1 @@
-Subproject commit 22fb9049e346c52a5f641fb54a196e8dac7f1da0
+Subproject commit ce68d100180a4fbcee5b76e2e2dc7eea43ccb856
diff --git a/simplified-app-palace/build.gradle.kts b/simplified-app-palace/build.gradle.kts
index 93a58388b..2efb676be 100644
--- a/simplified-app-palace/build.gradle.kts
+++ b/simplified-app-palace/build.gradle.kts
@@ -531,8 +531,6 @@ dependencies {
implementation(libs.kotlinx.datetime)
implementation(libs.logback.android)
implementation(libs.moznion.uribuildertiny)
- implementation(libs.nano.httpd)
- implementation(libs.nano.httpd.nanolets)
implementation(libs.nypl.readium)
implementation(libs.okhttp3)
implementation(libs.okio)
diff --git a/simplified-tests/build.gradle.kts b/simplified-tests/build.gradle.kts
index 312a7ff22..e990a117f 100644
--- a/simplified-tests/build.gradle.kts
+++ b/simplified-tests/build.gradle.kts
@@ -204,8 +204,6 @@ val dependencyObjects = listOf(
libs.mockito.android,
libs.mockito.core,
libs.mockito.kotlin,
- libs.nano.httpd,
- libs.nano.httpd.nanolets,
libs.nypl.readium,
libs.objenesis,
libs.okhttp3,
diff --git a/simplified-viewer-pdf-pdfjs/build.gradle.kts b/simplified-viewer-pdf-pdfjs/build.gradle.kts
index 4fa91443d..4cceae2ce 100644
--- a/simplified-viewer-pdf-pdfjs/build.gradle.kts
+++ b/simplified-viewer-pdf-pdfjs/build.gradle.kts
@@ -54,8 +54,6 @@ dependencies {
implementation(libs.kotlin.reflect)
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
- implementation(libs.nano.httpd)
- implementation(libs.nano.httpd.nanolets)
implementation(libs.palace.drm.core)
implementation(libs.palace.theme)
implementation(libs.pdfium.android)
diff --git a/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/PdfServer.kt b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/PdfServer.kt
index d8b24cc77..8ad042671 100644
--- a/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/PdfServer.kt
+++ b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/PdfServer.kt
@@ -3,6 +3,7 @@ package org.librarysimplified.viewer.pdf.pdfjs
import android.content.Context
import android.net.Uri
import kotlinx.coroutines.runBlocking
+import org.librarysimplified.viewer.pdf.pdfjs.factory.PdfDocumentFactory
import org.nanohttpd.protocols.http.IHTTPSession
import org.nanohttpd.protocols.http.response.Response
import org.nanohttpd.protocols.http.response.Status
@@ -53,6 +54,7 @@ class PdfServer private constructor(
),
PdfParser(
context = context,
+ pdfFactory = PdfDocumentFactory(context)
)
),
contentProtections = contentProtections,
diff --git a/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfDocumentFactory.kt b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfDocumentFactory.kt
new file mode 100644
index 000000000..db1013c3c
--- /dev/null
+++ b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfDocumentFactory.kt
@@ -0,0 +1,70 @@
+package org.librarysimplified.viewer.pdf.pdfjs.factory
+
+import android.content.Context
+import android.os.ParcelFileDescriptor
+import com.shockwave.pdfium.PdfDocument
+import com.shockwave.pdfium.PdfiumCore
+import org.readium.r2.shared.PdfSupport
+import org.readium.r2.shared.extensions.md5
+import org.readium.r2.shared.extensions.tryOrNull
+import org.readium.r2.shared.fetcher.Resource
+import org.readium.r2.shared.util.pdf.PdfDocumentFactory
+import org.readium.r2.shared.util.use
+import java.io.File
+import kotlin.reflect.KClass
+
+@OptIn(PdfSupport::class)
+class PdfDocumentFactory(context: Context) : PdfDocumentFactory {
+ override val documentType: KClass = PdfReaderDocument::class
+
+ private val core by lazy { PdfiumCore(context.applicationContext) }
+
+ override suspend fun open(file: File, password: String?): PdfReaderDocument {
+ return core.fromFile(file, password)
+ }
+
+ override suspend fun open(resource: Resource, password: String?): PdfReaderDocument {
+ return resource.openAsFile(password) ?: resource.openBytes(password)
+ }
+
+ private suspend fun Resource.openAsFile(password: String?): PdfReaderDocument? {
+ return file?.let {
+ tryOrNull { open(it, password) }
+ }
+ }
+
+ private suspend fun Resource.openBytes(password: String?): PdfReaderDocument {
+ return use {
+ core.fromBytes(read().getOrThrow(), password)
+ }
+ }
+
+ private fun PdfiumCore.fromFile(file: File, password: String?): PdfReaderDocument {
+ return fromDocument(
+ newDocument(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY), password),
+ identifier = file.md5()
+ )
+ }
+
+ /**
+ * Creates a [PdfReaderDocument] from raw bytes.
+ */
+ private fun PdfiumCore.fromBytes(bytes: ByteArray, password: String?): PdfReaderDocument {
+ return fromDocument(
+ newDocument(bytes, password),
+ identifier = bytes.md5()
+ )
+ }
+
+ private fun PdfiumCore.fromDocument(
+ document: PdfDocument,
+ identifier: String?
+ ): PdfReaderDocument {
+ return PdfReaderDocument(
+ core = this,
+ document = document,
+ identifier = identifier,
+ pageCount = getPageCount(document)
+ )
+ }
+}
diff --git a/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfReaderDocument.kt b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfReaderDocument.kt
new file mode 100644
index 000000000..ead15294c
--- /dev/null
+++ b/simplified-viewer-pdf-pdfjs/src/main/java/org/librarysimplified/viewer/pdf/pdfjs/factory/PdfReaderDocument.kt
@@ -0,0 +1,73 @@
+package org.librarysimplified.viewer.pdf.pdfjs.factory
+
+import android.content.Context
+import android.graphics.Bitmap
+import com.shockwave.pdfium.PdfiumCore
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.readium.r2.shared.PdfSupport
+import org.readium.r2.shared.util.pdf.PdfDocument
+import org.slf4j.LoggerFactory
+import com.shockwave.pdfium.PdfDocument as PdfiumDocument
+
+class PdfReaderDocument(
+ val core: PdfiumCore,
+ val document: PdfiumDocument,
+ override val identifier: String?,
+ override val pageCount: Int
+) : PdfDocument {
+
+ override val title: String?
+ get() = metadata.title
+
+ override val author: String?
+ get() = metadata.author
+
+ override val subject: String?
+ get() = metadata.subject
+
+ override val keywords: List
+ get() = metadata.keywords
+ .split(",")
+ .map { it.trim() }
+ .filter { it.isNotEmpty() }
+
+ private val logger = LoggerFactory.getLogger(PdfReaderDocument::class.java)
+ private val metadata: PdfiumDocument.Meta by lazy { core.getDocumentMeta(document) }
+
+ override suspend fun cover(context: Context): Bitmap? {
+ return withContext(Dispatchers.IO) {
+ try {
+ core.openPage(document, 0)
+ val width = core.getPageWidth(document, 0)
+ val height = core.getPageHeight(document, 0)
+ val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
+ core.renderPageBitmap(document, bitmap, 0, 0, 0, width, height, false)
+ bitmap
+ } catch (e: Exception) {
+ logger.error("Error rendering page: ", e)
+ null
+ } catch (e: OutOfMemoryError) {
+ logger.error("Error rendering page: ", e)
+ null
+ }
+ }
+ }
+
+ override val outline: List by lazy {
+ core.getTableOfContents(document).map { it.toOutlineNode() }
+ }
+
+ override suspend fun close() {
+ // do nothing
+ }
+
+ @OptIn(PdfSupport::class)
+ private fun PdfiumDocument.Bookmark.toOutlineNode(): PdfDocument.OutlineNode {
+ return PdfDocument.OutlineNode(
+ title = title,
+ pageNumber = pageIdx.toInt() + 1,
+ children = children.map { it.toOutlineNode() },
+ )
+ }
+}