gpt4 book ai didi

android - 使用 PdfRenderer 在 Jetpack Compose 中创建 PDF 查看器

转载 作者:行者123 更新时间:2023-12-04 23:57:22 27 4
gpt4 key购买 nike

我正在尝试使用 PdfRenderer 创建可组合的 PDF 查看器和 Coil用于将位图加载到 LazyColumn .
这是我到目前为止得到的:

@Composable
fun PdfViewer(
modifier: Modifier = Modifier,
uri: Uri,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp)
) {
val loaderScope = rememberCoroutineScope()
val renderer = remember(uri) {
val input = ParcelFileDescriptor.open(uri.toFile(), ParcelFileDescriptor.MODE_READ_ONLY)
PdfRenderer(input)
}
val context = LocalContext.current
val mutex = remember { Mutex() }
val imageLoader = LocalContext.current.imageLoader
BoxWithConstraints(modifier = modifier.fillMaxWidth()) {
val width = with(LocalDensity.current) { maxWidth.toPx() }.toInt()
val height = (width * sqrt(2f)).toInt()
LazyColumn(
verticalArrangement = verticalArrangement
) {
items(
count = renderer.pageCount,
key = { it }
) { index ->
val cacheKey = MemoryCache.Key("$uri-$index")
val bitmap = remember(uri, index) {
val cachedBitmap = imageLoader.memoryCache[cacheKey]
if (cachedBitmap != null) cachedBitmap else {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
loaderScope.launch(Dispatchers.IO) {
mutex.withLock {
Timber.d("Loading $uri - page $index")
renderer.openPage(index).use {
it.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
}
}
}
bitmap
}
}
val request = ImageRequest.Builder(context)
.size(width, height)
.memoryCacheKey(cacheKey)
.data(bitmap)
.build()

Image(
modifier = Modifier.background(Color.White).aspectRatio(1f / sqrt(2f)).fillMaxWidth(),
contentScale = ContentScale.Fit,
painter = rememberImagePainter(request),
contentDescription = "Page ${index + 1} of ${renderer.pageCount}"
)
}
}
}
}
这种工作,但是当第一次加载位图时,它不会显示在列表中,直到我滚动(即重绘之后)。我想利用 LazyColumn的功能并且仅在 PDF 页面可见时才加载它们。
有没有更好的方法来实现这一目标?

最佳答案

我设法解决它如下:

@Composable
fun PdfViewer(
modifier: Modifier = Modifier,
uri: Uri,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp)
) {
val rendererScope = rememberCoroutineScope()
val mutex = remember { Mutex() }
val renderer by produceState<PdfRenderer?>(null, uri) {
rendererScope.launch(Dispatchers.IO) {
val input = ParcelFileDescriptor.open(uri.toFile(), ParcelFileDescriptor.MODE_READ_ONLY)
value = PdfRenderer(input)
}
awaitDispose {
val currentRenderer = value
rendererScope.launch(Dispatchers.IO) {
mutex.withLock {
currentRenderer?.close()
}
}
}
}
val context = LocalContext.current
val imageLoader = LocalContext.current.imageLoader
val imageLoadingScope = rememberCoroutineScope()
BoxWithConstraints(modifier = modifier.fillMaxWidth()) {
val width = with(LocalDensity.current) { maxWidth.toPx() }.toInt()
val height = (width * sqrt(2f)).toInt()
val pageCount by remember(renderer) { derivedStateOf { renderer?.pageCount ?: 0 } }
LazyColumn(
verticalArrangement = verticalArrangement
) {
items(
count = pageCount,
key = { index -> "$uri-$index" }
) { index ->
val cacheKey = MemoryCache.Key("$uri-$index")
var bitmap by remember { mutableStateOf(imageLoader.memoryCache[cacheKey]) }
if (bitmap == null) {
DisposableEffect(uri, index) {
val job = imageLoadingScope.launch(Dispatchers.IO) {
val destinationBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
mutex.withLock {
Timber.d("Loading PDF $uri - page $index/$pageCount")
if (!coroutineContext.isActive) return@launch
try {
renderer?.let {
it.openPage(index).use { page ->
page.render(
destinationBitmap,
null,
null,
PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY
)
}
}
} catch (e: Exception) {
//Just catch and return in case the renderer is being closed
return@launch
}
}
bitmap = destinationBitmap
}
onDispose {
job.cancel()
}
}
Box(modifier = Modifier.background(Color.White).aspectRatio(1f / sqrt(2f)).fillMaxWidth())
} else {
val request = ImageRequest.Builder(context)
.size(width, height)
.memoryCacheKey(cacheKey)
.data(bitmap)
.build()

Image(
modifier = Modifier.background(Color.White).aspectRatio(1f / sqrt(2f)).fillMaxWidth(),
contentScale = ContentScale.Fit,
painter = rememberImagePainter(request),
contentDescription = "Page ${index + 1} of $pageCount"
)
}
}
}
}
}
这也应该处理 pdf 渲染器的处置。

关于android - 使用 PdfRenderer 在 Jetpack Compose 中创建 PDF 查看器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69943176/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com