Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ dependencies {

implementation("com.google.android.material:material:1.12.0")
implementation("androidx.test.espresso:espresso-contrib:3.6.1")
val kotlin_version = "1.9.21"
val kotlin_version = "2.1.10"
implementation(kotlin("stdlib"))
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
//noinspection GradleDependency
Expand Down
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

plugins {
id("com.android.application") version "8.8.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
id("com.android.library") version "8.8.1" apply false
id("com.android.application") version "8.9.0" apply false
id("org.jetbrains.kotlin.android") version "2.1.10" apply false
id("com.android.library") version "8.9.0" apply false
}
5 changes: 3 additions & 2 deletions pdfViewer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.vanniktech.maven.publish.SonatypeHost
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
id("kotlin-parcelize")
id("org.jetbrains.dokka") version "1.9.20"
id("com.vanniktech.maven.publish") version "0.28.0"
Expand Down Expand Up @@ -52,7 +53,7 @@ android {

dependencies {
implementation("androidx.compose.material3:material3-android:1.3.1")
val kotlin_version = "1.9.21"
val kotlin_version = "2.1.10"
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
implementation("androidx.core:core-ktx:1.15.0")
Expand Down Expand Up @@ -121,4 +122,4 @@ mavenPublishing {
}
}

}
}
30 changes: 9 additions & 21 deletions pdfViewer/src/main/java/com/rajat/pdfviewer/PdfRendererCore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.abs

open class PdfRendererCore(
private val context: Context,
Expand Down Expand Up @@ -84,19 +83,19 @@ open class PdfRendererCore(

fun renderPage(
pageNo: Int,
bitmap: Bitmap,
onBitmapReady: ((success: Boolean, pageNo: Int, bitmap: Bitmap?) -> Unit)? = null
size: Size,
onBitmapReady: ((pageNo: Int, bitmap: Bitmap?) -> Unit)? = null
) {
val startTime = System.nanoTime()

if (pageNo >= getPageCount()) {
onBitmapReady?.invoke(false, pageNo, null)
onBitmapReady?.invoke(pageNo, null)
return
}

getBitmapFromCache(pageNo)?.let { cachedBitmap ->
scope.launch(Dispatchers.Main) {
onBitmapReady?.invoke(true, pageNo, cachedBitmap)
onBitmapReady?.invoke(pageNo, cachedBitmap)
if (enableDebugMetrics) {
Log.d("PdfRendererCore", "Page $pageNo loaded from cache")
}
Expand All @@ -108,7 +107,6 @@ open class PdfRendererCore(

renderJobs[pageNo]?.cancel()
renderJobs[pageNo] = scope.launch {
var success = false
var renderedBitmap: Bitmap? = null

renderLock.withLock {
Expand All @@ -117,14 +115,13 @@ open class PdfRendererCore(

try {
val aspectRatio = pdfPage.width.toFloat() / pdfPage.height
val height = bitmap.height
val height = size.height
val width = (height * aspectRatio).toInt()

val tempBitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, height)
pdfPage.render(tempBitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)

addBitmapToMemoryCache(pageNo, tempBitmap)
success = true
renderedBitmap = tempBitmap

} catch (e: Exception) {
Expand All @@ -144,26 +141,19 @@ open class PdfRendererCore(
updateAggregateMetrics(pageNo, renderTime)

withContext(Dispatchers.Main) {
onBitmapReady?.invoke(success, pageNo, renderedBitmap)
onBitmapReady?.invoke(pageNo, renderedBitmap)
}
}
}

suspend fun renderPageAsync(pageNo: Int, width: Int, height: Int): Bitmap? {
return suspendCancellableCoroutine { continuation ->
val bitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, height)
renderPage(pageNo, bitmap) { success, _, renderedBitmap ->
if (success) {
continuation.resume(renderedBitmap ?: bitmap, null)
} else {
CommonUtils.Companion.BitmapPool.recycleBitmap(bitmap)
continuation.resume(null, null)
}
renderPage(pageNo, Size(width, maxOf(1, height))) { _, renderedBitmap ->
continuation.resume(renderedBitmap, null)
}
}
}


private fun updateAggregateMetrics(page: Int, duration: Long) {
totalPagesRendered++
totalRenderTime += duration
Expand All @@ -186,9 +176,7 @@ open class PdfRendererCore(
if (renderJobs[pageNo]?.isActive != true) {
renderJobs[pageNo]?.cancel()
renderJobs[pageNo] = scope.launch {
val bitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, height)
renderPage(pageNo, bitmap) { success, _, _ ->
if (!success) CommonUtils.Companion.BitmapPool.recycleBitmap(bitmap)
renderPage(pageNo, Size(width, maxOf(1, height))) { _, _ ->
}
}
}
Expand Down
52 changes: 44 additions & 8 deletions pdfViewer/src/main/java/com/rajat/pdfviewer/PdfViewAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package com.rajat.pdfviewer

import android.content.Context
import android.graphics.Rect
//import android.util.Log
import android.util.Size
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AlphaAnimation
import android.view.animation.LinearInterpolator
import androidx.recyclerview.widget.RecyclerView
import com.rajat.pdfviewer.databinding.ListItemPdfPageBinding
import com.rajat.pdfviewer.util.CommonUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -34,9 +35,47 @@ internal class PdfViewAdapter(
holder.bind(position)
}

override fun onViewRecycled(holder: PdfPageViewHolder) {
holder.recycle()
}

override fun onViewDetachedFromWindow(holder: PdfPageViewHolder) {
holder.detach()
}

override fun onViewAttachedToWindow(holder: PdfPageViewHolder) {
holder.attach(holder.bindingAdapterPosition)
}

inner class PdfPageViewHolder(private val itemBinding: ListItemPdfPageBinding) : RecyclerView.ViewHolder(itemBinding.root) {
private var detached = false

private fun clearBitmap() {
with(itemBinding) {
pageView.setImageBitmap(null);
}
detached = true
}

fun attach(position: Int) {
// Log.d("PdfViewAdapter", "Attached to window: $bindingAdapterPosition")
if ( detached )
bind(position)
}

fun detach() {
// Log.d("PdfViewAdapter", "Detached from window: $bindingAdapterPosition")
clearBitmap()
}

fun recycle() {
// Log.d("PdfViewAdapter", "Recycled page: $bindingAdapterPosition")
clearBitmap()
}

fun bind(position: Int) {
with(itemBinding) {
// Log.d("PdfViewAdapter", "Binding page: $position")
pageLoadingLayout.pdfViewPageLoadingProgress.visibility = if (enableLoadingForPages) View.VISIBLE else View.GONE

// Before we trigger rendering, explicitly ensure that cached bitmaps are used
Expand All @@ -54,24 +93,21 @@ internal class PdfViewAdapter(

updateLayoutParams(height)

val bitmap = CommonUtils.Companion.BitmapPool.getBitmap(width, maxOf(1, height))
renderer.renderPage(position, bitmap) { success, pageNo, renderedBitmap ->
if (success && pageNo == position) {
renderer.renderPage(position, Size(width, maxOf(1, height))) { pageNo, renderedBitmap ->
if (renderedBitmap != null && pageNo == position) {
CoroutineScope(Dispatchers.Main).launch {
pageView.setImageBitmap(renderedBitmap ?: bitmap)
pageView.setImageBitmap(renderedBitmap)
applyFadeInAnimation(pageView)
pageLoadingLayout.pdfViewPageLoadingProgress.visibility = View.GONE
[email protected] = false

// Prefetch here
renderer.prefetchPagesAround(
currentPage = position,
width = pageView.width.takeIf { it > 0 } ?: context.resources.displayMetrics.widthPixels,
height = pageView.height.takeIf { it > 0 } ?: context.resources.displayMetrics.heightPixels
)

}
} else {
CommonUtils.Companion.BitmapPool.recycleBitmap(bitmap)
}
}
}
Expand Down
Loading