Update dependencies
This commit is contained in:
parent
86e12449f7
commit
9a2b5ce297
|
@ -3,10 +3,10 @@ Minimum Viable Goals:
|
|||
- [x] Continuous Horizontal Scroll - unreasonably rare feature
|
||||
- [x] Presentation View - i.e. show on an external monitor - haven't seen another app do this yet!
|
||||
- [x] Immersive View - no system status bar etc.
|
||||
- [x] Autocrop margins
|
||||
- [ ] Open files the Android way - currently just a bundled test file
|
||||
- [ ] Delete+Reorder Pages - doesn't have to save the source file, but does need to save a change journal
|
||||
- [ ] Text Annotations - as above
|
||||
- [ ] Autocrop margins
|
||||
|
||||
Stretch Goals:
|
||||
- [ ] Networked View:
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
package com.lhw.pdf
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RectF
|
||||
import android.graphics.pdf.PdfRenderer
|
||||
import android.os.ParcelFileDescriptor
|
||||
import androidx.core.graphics.times
|
||||
import java.io.File
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class PdfDocument(private val fileCached: File, private val autoCrop: Boolean = false) {
|
||||
private val pfd = ParcelFileDescriptor.open(fileCached, ParcelFileDescriptor.MODE_READ_ONLY)
|
||||
private val renderer = PdfRenderer(pfd)
|
||||
val bitmapThumbnails = mutableMapOf<Int, Bitmap>()
|
||||
val bitmapPagesMain = mutableMapOf<Int, Bitmap>()
|
||||
val bitmapPagesPresentation = mutableMapOf<Int, Bitmap>()
|
||||
private val pagePtWidths = mutableListOf<Int>()
|
||||
private val pagePtHeights = mutableListOf<Int>()
|
||||
private val pageAutoCropRects = mutableListOf<RectF>()
|
||||
// Due to the way thumbnails render, the bottom right is more likely to be cut off
|
||||
private val autoCropSafetyMarginUpper = 2
|
||||
private val autoCropSafetyMarginLower = 16
|
||||
|
||||
init {
|
||||
val numPages = renderer.pageCount
|
||||
for (i in 0..<numPages) {
|
||||
val page = renderer.openPage(i)
|
||||
pagePtWidths.add(page.width)
|
||||
pagePtHeights.add(page.height)
|
||||
page.close()
|
||||
}
|
||||
}
|
||||
|
||||
private val rectFIdentity = RectF(0F, 0F, 1F, 1F)
|
||||
private fun renderPage(index: Int, maxWidth: Int, maxHeight: Int, crop: Boolean = false): Bitmap {
|
||||
val cropRect = if (!crop || pageAutoCropRects.size <= index) rectFIdentity else pageAutoCropRects[index]
|
||||
val ptWidth = pagePtWidths[index] * cropRect.width()
|
||||
val ptHeight = pagePtHeights[index] * cropRect.height()
|
||||
val widthFromMaxHeight = (ptWidth * maxHeight/ptHeight).toInt()
|
||||
val heightFromMaxWidth = (ptHeight * maxWidth/ptWidth).toInt()
|
||||
val (width, height) = if (widthFromMaxHeight > maxWidth) Pair(maxWidth, heightFromMaxWidth) else Pair(widthFromMaxHeight, maxHeight)
|
||||
|
||||
val page = renderer.openPage(index)
|
||||
println("Creating page $index bitmap with width $width and height $height from cropRect $cropRect")
|
||||
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||
val ptToPixel = height/ptHeight
|
||||
val transform = Matrix()
|
||||
val transposePtX = -cropRect.left * ptWidth
|
||||
val transposePtY = -cropRect.top * ptHeight
|
||||
transform.setValues(floatArrayOf(ptToPixel, 0F, transposePtX*ptToPixel, 0F, ptToPixel, transposePtY*ptToPixel, 0F, 0F, 1F))
|
||||
page.render(bitmap, null, transform, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
|
||||
page.close()
|
||||
return bitmap
|
||||
}
|
||||
|
||||
private fun renderPagesToMap(map: MutableMap<Int, Bitmap>, width: Int, height: Int, crop: Boolean = false) {
|
||||
map.clear()
|
||||
val numPages = renderer.pageCount
|
||||
for (i in 0..<numPages) {
|
||||
map[i] = renderPage(i, width, height, crop)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isColorContent(c: Int): Boolean {
|
||||
val color = Color.valueOf(c)
|
||||
return (color.alpha() > 0) && (color.luminance() < 0.9F)
|
||||
}
|
||||
fun renderThumbnails(width: Int, height: Int) {
|
||||
renderPagesToMap(bitmapThumbnails, width, height)
|
||||
println("Thumbnails rendered")
|
||||
if (autoCrop) {
|
||||
println("Auto cropping from thumbnails")
|
||||
val numPages = renderer.pageCount
|
||||
pageAutoCropRects.clear()
|
||||
for (i in 0..<numPages) {
|
||||
println("Auto cropping page $i from thumbnail")
|
||||
val bitmap = bitmapThumbnails[i]!!
|
||||
val w = bitmap.width
|
||||
val h = bitmap.height
|
||||
val rect = Rect()
|
||||
val rectF = RectF(rectFIdentity)
|
||||
// Find first row
|
||||
top@ for (y in 0..<h) {
|
||||
for (x in 0..<w) {
|
||||
val c = bitmap.getPixel(x, y)
|
||||
// println("Auto crop checking pixel $x $y == $c")
|
||||
if (isColorContent(c)) {
|
||||
rect.top = max(y-autoCropSafetyMarginUpper, 0)
|
||||
rectF.top = rect.top/h.toFloat()
|
||||
break@top
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find last row
|
||||
bottom@ for (y in (h-1) downTo 0) {
|
||||
for (x in 0..<w) {
|
||||
val c = bitmap.getPixel(x, y)
|
||||
if (isColorContent(c)) {
|
||||
rect.bottom = min(y+autoCropSafetyMarginLower, h-1)
|
||||
rectF.bottom = (rect.bottom+1)/h.toFloat()
|
||||
break@bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find first column
|
||||
left@ for (x in 0..<w) {
|
||||
for (y in rect.top..rect.bottom) {
|
||||
val c = bitmap.getPixel(x, y)
|
||||
if (isColorContent(c)) {
|
||||
rect.left = max(x-autoCropSafetyMarginUpper, 0)
|
||||
rectF.left = rect.left/w.toFloat()
|
||||
break@left
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find last column
|
||||
right@ for (x in (w-1) downTo 0) {
|
||||
for (y in rect.top..rect.bottom) {
|
||||
val c = bitmap.getPixel(x, y)
|
||||
if (isColorContent(c)) {
|
||||
rect.right = min(x+autoCropSafetyMarginLower, w-1)
|
||||
rectF.right = (rect.right+1)/w.toFloat()
|
||||
break@right
|
||||
}
|
||||
}
|
||||
}
|
||||
println("Auto crop found margins of page $i at $rect, scales to $rectF")
|
||||
pageAutoCropRects.add(rectF)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renderPagesMain(width: Int, height: Int) {
|
||||
renderPagesToMap(bitmapPagesMain, width, height, true)
|
||||
}
|
||||
|
||||
fun renderPagesPresentation(width: Int, height: Int) {
|
||||
renderPagesToMap(bitmapPagesPresentation, width, height, true)
|
||||
}
|
||||
}
|
|
@ -3,15 +3,15 @@ agp = "8.5.2"
|
|||
kotlin = "1.9.0"
|
||||
coreKtx = "1.13.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
appcompat = "1.7.0"
|
||||
material = "1.10.0"
|
||||
material = "1.12.0"
|
||||
constraintlayout = "2.1.4"
|
||||
lifecycleLivedataKtx = "2.6.1"
|
||||
lifecycleViewmodelKtx = "2.6.1"
|
||||
navigationFragmentKtx = "2.6.0"
|
||||
navigationUiKtx = "2.6.0"
|
||||
lifecycleLivedataKtx = "2.8.4"
|
||||
lifecycleViewmodelKtx = "2.8.4"
|
||||
navigationFragmentKtx = "2.7.7"
|
||||
navigationUiKtx = "2.7.7"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
|
Loading…
Reference in New Issue