Fix rotation for pages migrated from previous versions of the app
This commit is contained in:
@@ -30,7 +30,6 @@ import kotlinx.coroutines.launch
|
||||
import org.fairscan.app.data.ImageRepository
|
||||
import org.fairscan.app.domain.CapturedPage
|
||||
import org.fairscan.app.domain.PageViewKey
|
||||
import org.fairscan.app.domain.Rotation
|
||||
import org.fairscan.app.ui.NavigationState
|
||||
import org.fairscan.app.ui.Screen
|
||||
import org.fairscan.app.ui.state.DocumentUiModel
|
||||
@@ -47,7 +46,7 @@ class MainViewModel(val imageRepository: ImageRepository, launchMode: LaunchMode
|
||||
_pages.map { pages ->
|
||||
DocumentUiModel(
|
||||
pageKeys = pages.map { p ->
|
||||
PageViewKey(p.id, p.metadata?.manualRotation?: Rotation.R0)
|
||||
PageViewKey(p.id, p.manualRotation)
|
||||
}.toImmutableList(),
|
||||
imageLoader = ::getBitmap,
|
||||
thumbnailLoader = ::getThumbnail,
|
||||
|
||||
@@ -122,8 +122,11 @@ class ImageRepository(
|
||||
}
|
||||
|
||||
fun pages(): List<ScanPage> =
|
||||
pages.pages().map {
|
||||
ScanPage(it.id, it.toMetadata())
|
||||
pages.pages().mapNotNull {
|
||||
runCatching {
|
||||
val manualRotation = Rotation.fromDegrees(it.manualRotationDegrees)
|
||||
ScanPage(it.id, manualRotation, it.toMetadata())
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun page(id: String): PageV2? = pages.get(id)
|
||||
@@ -140,7 +143,7 @@ class ImageRepository(
|
||||
id = id,
|
||||
quad = metadata.normalizedQuad.toSerializable(),
|
||||
baseRotationDegrees = metadata.baseRotation.degrees,
|
||||
manualRotationDegrees = metadata.manualRotation.degrees,
|
||||
manualRotationDegrees = Rotation.R0.degrees,
|
||||
isColored = metadata.isColored
|
||||
)
|
||||
)
|
||||
@@ -321,13 +324,10 @@ fun NormalizedQuad.toQuad(): Quad =
|
||||
)
|
||||
|
||||
fun PageV2.toMetadata(): PageMetadata? {
|
||||
return runCatching {
|
||||
if (quad == null || isColored == null) return null
|
||||
PageMetadata(
|
||||
return PageMetadata(
|
||||
quad.toQuad(),
|
||||
Rotation.fromDegrees(baseRotationDegrees),
|
||||
Rotation.fromDegrees(manualRotationDegrees),
|
||||
isColored
|
||||
)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ fun jpegsForExport(
|
||||
ExportQuality.HIGH -> pages.mapNotNull { page ->
|
||||
val sourceJpegBytes = imageRepository.sourceJpegBytes(page.id)
|
||||
val pageMetadata = page.metadata
|
||||
val manualRotation = page.manualRotation
|
||||
if (sourceJpegBytes != null && pageMetadata != null)
|
||||
prepareJpegForHigh(sourceJpegBytes, pageMetadata, exportQuality)
|
||||
prepareJpegForHigh(sourceJpegBytes, pageMetadata, manualRotation, exportQuality)
|
||||
else
|
||||
imageRepository.jpegBytes(page.id)
|
||||
}
|
||||
@@ -73,6 +74,7 @@ fun resizeJpegBytesForMaxPixels(
|
||||
fun prepareJpegForHigh(
|
||||
sourceJpegBytes: ByteArray,
|
||||
pageMetadata: PageMetadata,
|
||||
manualRotation: Rotation,
|
||||
exportQuality: ExportQuality,
|
||||
): ByteArray? {
|
||||
|
||||
@@ -84,7 +86,7 @@ fun prepareJpegForHigh(
|
||||
val page = extractDocument(
|
||||
decoded,
|
||||
quad,
|
||||
pageMetadata.baseRotation.add(pageMetadata.manualRotation).degrees,
|
||||
pageMetadata.baseRotation.add(manualRotation).degrees,
|
||||
pageMetadata.isColored,
|
||||
exportQuality.maxPixels)
|
||||
val outJpegBytes = encodeJpeg(page, exportQuality.jpegQuality)
|
||||
|
||||
@@ -19,12 +19,12 @@ import org.fairscan.imageprocessing.Quad
|
||||
data class PageMetadata(
|
||||
val normalizedQuad: Quad,
|
||||
val baseRotation: Rotation,
|
||||
val manualRotation: Rotation,
|
||||
val isColored: Boolean,
|
||||
)
|
||||
|
||||
data class ScanPage(
|
||||
val id: String,
|
||||
val manualRotation: Rotation,
|
||||
val metadata: PageMetadata?,
|
||||
)
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@ fun CameraScreenPreviewWithProcessedImage() {
|
||||
CapturedPage(
|
||||
debugImage("gallica.bnf.fr-bpt6k5530456s-1.jpg"),
|
||||
debugImage("gallica.bnf.fr-bpt6k5530456s-1.jpg"),
|
||||
PageMetadata(quad, R0, R0, false))))
|
||||
PageMetadata(quad, R0, false))))
|
||||
}
|
||||
|
||||
@Preview(showBackground = true, widthDp = 640, heightDp = 320)
|
||||
|
||||
@@ -198,7 +198,7 @@ fun extractDocumentFromBitmap(
|
||||
outBgr.release()
|
||||
val normalizedQuad = quad.scaledTo(source.width, source.height, 1, 1)
|
||||
val baseRotation = Rotation.fromDegrees(rotationDegrees)
|
||||
val metadata = PageMetadata(normalizedQuad, baseRotation, Rotation.R0, isColored)
|
||||
val metadata = PageMetadata(normalizedQuad, baseRotation, isColored)
|
||||
return CapturedPage(outBitmap, source, metadata)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class ImageRepositoryTest {
|
||||
private var _filesDir: File? = null
|
||||
|
||||
val quad1 = Quad(Point(.01, .02), Point(.1, .03), Point(.11, .12), Point(.03, .09))
|
||||
val metadata1 = PageMetadata(quad1, R90, R0, true)
|
||||
val metadata1 = PageMetadata(quad1, R90, true)
|
||||
|
||||
fun getFilesDir(): File {
|
||||
if (_filesDir == null) {
|
||||
@@ -73,11 +73,11 @@ class ImageRepositoryTest {
|
||||
|
||||
val page = repo.pages().first()
|
||||
assertThat(page.id).isEqualTo(id)
|
||||
assertThat(page.manualRotation).isEqualTo(R0)
|
||||
val metadata = page.metadata
|
||||
assertThat(metadata).isNotNull()
|
||||
assertThat(metadata!!.normalizedQuad).isEqualTo(quad1)
|
||||
assertThat(metadata.baseRotation).isEqualTo(metadata1.baseRotation)
|
||||
assertThat(metadata.manualRotation).isEqualTo(metadata1.manualRotation)
|
||||
assertThat(metadata.isColored).isEqualTo(metadata1.isColored)
|
||||
}
|
||||
|
||||
@@ -192,19 +192,18 @@ class ImageRepositoryTest {
|
||||
fun rotate() {
|
||||
val repo = repo()
|
||||
repo.add(byteArrayOf(101, 102, 103), byteArrayOf(51), metadata1)
|
||||
assertThat(metadata1.manualRotation).isEqualTo(R0)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1)
|
||||
val id = repo.pages().last().id
|
||||
repo.rotate(id, true)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1.copy(manualRotation = R90))
|
||||
assertThat(repo.pages().last().manualRotation).isEqualTo(R90)
|
||||
repo.rotate(id, true)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1.copy(manualRotation = R180))
|
||||
assertThat(repo.pages().last().manualRotation).isEqualTo(R180)
|
||||
repo.rotate(id, true)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1.copy(manualRotation = R270))
|
||||
assertThat(repo.pages().last().manualRotation).isEqualTo(R270)
|
||||
repo.rotate(id, true)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1.copy(manualRotation = R0))
|
||||
assertThat(repo.pages().last().manualRotation).isEqualTo(R0)
|
||||
repo.rotate(id, false)
|
||||
assertThat(repo.pages().last().metadata).isEqualTo(metadata1.copy(manualRotation = R270))
|
||||
assertThat(repo.pages().last().manualRotation).isEqualTo(R270)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -248,8 +247,21 @@ class ImageRepositoryTest {
|
||||
assertThat(metadata).isNotNull()
|
||||
assertThat(metadata!!.isColored).isEqualTo(isColored)
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(PageV2("1", 42, 0, quad, true).toMetadata()).isNull()
|
||||
@Test
|
||||
fun `pages with invalid metadata should be skipped`() {
|
||||
val bytes = byteArrayOf(105, 106, 107)
|
||||
|
||||
writeDocumentDotJson("""{"version":2, "pages":[{"id":"1", "manualRotationDegrees":90}]}""")
|
||||
File(scanDir(), "1.jpg").writeBytes(byteArrayOf(101))
|
||||
File(scanDir(), "1-90.jpg").writeBytes(bytes)
|
||||
assertThat(repo().imageIds()).containsExactly("1")
|
||||
|
||||
writeDocumentDotJson("""{"version":2, "pages":[{"id":"1", "manualRotationDegrees":42}]}""")
|
||||
File(scanDir(), "1.jpg").writeBytes(byteArrayOf(101))
|
||||
File(scanDir(), "1-42.jpg").writeBytes(bytes)
|
||||
assertThat(repo().imageIds()).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user