11package io.bashpsk.emptylibs.pdfviewer.pdf
22
33import android.content.Context
4- import android.graphics.Canvas
54import android.graphics.pdf.PdfRenderer
65import android.os.ParcelFileDescriptor
76import android.util.Log
@@ -14,16 +13,20 @@ import androidx.compose.runtime.mutableIntStateOf
1413import androidx.compose.runtime.mutableStateOf
1514import androidx.compose.runtime.retain.retain
1615import androidx.compose.runtime.setValue
16+ import androidx.compose.ui.graphics.Canvas
1717import androidx.compose.ui.graphics.Color
1818import androidx.compose.ui.graphics.ImageBitmap
19- import androidx.compose.ui.graphics.asImageBitmap
20- import androidx.compose.ui.graphics.toArgb
19+ import androidx.compose.ui.graphics.asAndroidBitmap
20+ import androidx.compose.ui.graphics.drawscope.CanvasDrawScope
2121import androidx.compose.ui.platform.LocalContext
22- import androidx.core.graphics.createBitmap
22+ import androidx.compose.ui.platform.LocalDensity
23+ import androidx.compose.ui.unit.Density
24+ import androidx.compose.ui.unit.LayoutDirection
2325import io.bashpsk.emptylibs.formatter.format.EmptyFormat
2426import io.bashpsk.emptylibs.formatter.resolution.ResolutionType
2527import io.bashpsk.emptylibs.gestureui.transform.TransformableGesturesState
2628import io.bashpsk.emptylibs.gestureui.transform.rememberTransformableGesturesState
29+ import io.bashpsk.emptylibs.imageutils.extension.toSize
2730import io.bashpsk.emptylibs.lrucachemanager.manager.EmptyCacheManager
2831import io.bashpsk.emptylibs.pdfviewer.page.PdfPageData
2932import io.bashpsk.emptylibs.pdfviewer.page.PdfScaledPageData
@@ -36,7 +39,6 @@ import kotlinx.coroutines.CoroutineScope
3639import kotlinx.coroutines.Dispatchers
3740import kotlinx.coroutines.Job
3841import kotlinx.coroutines.SupervisorJob
39- import kotlinx.coroutines.async
4042import kotlinx.coroutines.currentCoroutineContext
4143import kotlinx.coroutines.ensureActive
4244import kotlinx.coroutines.launch
@@ -67,6 +69,7 @@ fun rememberPdfLazyColumnState(
6769): PdfLazyColumnState {
6870
6971 val context = LocalContext .current
72+ val density = LocalDensity .current
7073
7174 val transformableState = rememberTransformableGesturesState(
7275 initialZoom = initialZoom,
@@ -77,8 +80,8 @@ fun rememberPdfLazyColumnState(
7780 zoomRange = zoomRange
7881 )
7982
80- val state = retain(transformableState) {
81- PdfLazyColumnState (transformable = transformableState)
83+ val state = retain(density, transformableState) {
84+ PdfLazyColumnState (density = density, transformable = transformableState)
8285 }
8386
8487 LaunchedEffect (cacheSize) {
@@ -99,10 +102,14 @@ fun rememberPdfLazyColumnState(
99102/* *
100103 * A state object that can be hoisted to control and observe scrolling and zooming of a PDF.
101104 *
105+ * @param density The density of the display.
102106 * @param transformable The state for transformable gestures.
103107 */
104108@Stable
105- class PdfLazyColumnState (internal val transformable : TransformableGesturesState ) {
109+ class PdfLazyColumnState (
110+ internal val density : Density ,
111+ internal val transformable : TransformableGesturesState
112+ ) {
106113
107114 /* *
108115 * A mutex to ensure thread-safe access to PDF rendering operations.
@@ -237,10 +244,12 @@ class PdfLazyColumnState(internal val transformable: TransformableGesturesState)
237244 *
238245 * @param pageIndex The index of the page to render.
239246 */
240- internal fun setRenderNormalBitmap (pageIndex : Int ) = coroutineScope.launch(Dispatchers .IO ) {
247+ internal suspend fun setRenderNormalBitmap (
248+ pageIndex : Int
249+ ) = withContext(context = Dispatchers .IO ) {
241250
242- val renderer = pdfRenderer ? : return @launch
243- val pageData = pageDataList[pageIndex] ? : return @launch
251+ val renderer = pdfRenderer ? : return @withContext
252+ val pageData = pageDataList[pageIndex] ? : return @withContext
244253
245254 val targetWidth = containerWidth * transformable.initialZoom.toInt()
246255 val targetHeight = ((targetWidth.toFloat() / pageData.width) * pageData.height).toInt()
@@ -270,12 +279,12 @@ class PdfLazyColumnState(internal val transformable: TransformableGesturesState)
270279 */
271280 internal suspend fun getScaledImageBitmap (
272281 pageIndex : Int
273- ): ImageBitmap ? = coroutineScope.async (context = Dispatchers .IO ) {
282+ ): ImageBitmap ? = withContext (context = Dispatchers .IO ) {
274283
275284 if (hasNeedScaledBitmap(pageData = getScaledPageData(pageIndex = pageIndex))) {
276285
277- val renderer = pdfRenderer ? : return @async null
278- val pageData = pageDataList[pageIndex] ? : return @async null
286+ val renderer = pdfRenderer ? : return @withContext null
287+ val pageData = pageDataList[pageIndex] ? : return @withContext null
279288
280289 val quality = findContentQuality()
281290 val targetWidth = (containerWidth * quality).toInt().coerceAtMost(
@@ -301,21 +310,25 @@ class PdfLazyColumnState(internal val transformable: TransformableGesturesState)
301310 }
302311
303312 getScaledPageData(pageIndex = pageIndex)?.bitmap
304- }.await()
313+ }
305314
306315 /* *
307316 * Updates the expansion state of the search interface.
308317 *
309318 * @param isExpanded Whether the search bar should be expanded or collapsed.
310319 */
311- internal fun onSearchExpandedChange (isExpanded : Boolean ) { isSearchExpanded = isExpanded }
320+ internal fun onSearchExpandedChange (isExpanded : Boolean ) {
321+ isSearchExpanded = isExpanded
322+ }
312323
313324 /* *
314325 * Updates the current search query string.
315326 *
316327 * @param query The new search string to be stored in [searchQuery].
317328 */
318- internal fun onSearchQueryChange (query : String ) { searchQuery = query }
329+ internal fun onSearchQueryChange (query : String ) {
330+ searchQuery = query
331+ }
319332
320333 /* *
321334 * Performs a text search across all pages of the PDF.
@@ -433,15 +446,26 @@ class PdfLazyColumnState(internal val transformable: TransformableGesturesState)
433446
434447 if (targetWidth <= 0 || targetHeight <= 0 ) return @use null
435448
436- val newBitmap = createBitmap (width = targetWidth, height = targetHeight)
449+ val newImageBitmap = ImageBitmap (width = targetWidth, height = targetHeight)
437450
438- Canvas (newBitmap).apply {
451+ CanvasDrawScope ().draw(
452+ density = density,
453+ layoutDirection = LayoutDirection .Ltr ,
454+ canvas = Canvas (image = newImageBitmap),
455+ size = newImageBitmap.toSize()
456+ ) {
439457
440- drawColor( Color .White .toArgb() )
458+ drawRect(color = Color .White )
441459 }
442460
443- pdfPage.render(newBitmap, null , null , PdfRenderer .Page .RENDER_MODE_FOR_DISPLAY )
444- newBitmap.asImageBitmap()
461+ pdfPage.render(
462+ newImageBitmap.asAndroidBitmap(),
463+ null ,
464+ null ,
465+ PdfRenderer .Page .RENDER_MODE_FOR_DISPLAY
466+ )
467+
468+ newImageBitmap
445469 }
446470 }
447471 }
0 commit comments