Encode icons in PNG, because JPEG doesn't support transparency
This caused black squares around icons.
This commit is contained in:
parent
682afa1c69
commit
9422d0d309
2 changed files with 25 additions and 7 deletions
|
@ -5,10 +5,14 @@
|
||||||
|
|
||||||
package com.stevesoltys.seedvault.worker
|
package com.stevesoltys.seedvault.worker
|
||||||
|
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.github.luben.zstd.ZstdOutputStream
|
||||||
import com.google.protobuf.ByteString
|
import com.google.protobuf.ByteString
|
||||||
|
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
||||||
|
import com.stevesoltys.seedvault.metadata.BackupType
|
||||||
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
|
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.repo.BackupData
|
import com.stevesoltys.seedvault.repo.BackupData
|
||||||
|
@ -32,6 +36,7 @@ import org.junit.runner.RunWith
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.inject
|
import org.koin.core.component.inject
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@ -76,6 +81,11 @@ class IconManagerTest : KoinComponent {
|
||||||
iconManager.uploadIcons()
|
iconManager.uploadIcons()
|
||||||
assertTrue(output.captured.isNotEmpty())
|
assertTrue(output.captured.isNotEmpty())
|
||||||
|
|
||||||
|
// @pm@ is needed
|
||||||
|
val pmPackageInfo = PackageInfo().apply { packageName = MAGIC_PACKAGE_MANAGER }
|
||||||
|
val backupData = BackupData(emptyList(), emptyMap())
|
||||||
|
snapshotCreator.onPackageBackedUp(pmPackageInfo, BackupType.KV, backupData)
|
||||||
|
|
||||||
// get snapshot and assert it has icon chunks
|
// get snapshot and assert it has icon chunks
|
||||||
val snapshot = snapshotCreator.finalizeSnapshot()
|
val snapshot = snapshotCreator.finalizeSnapshot()
|
||||||
assertTrue(snapshot.iconChunkIdsCount > 0)
|
assertTrue(snapshot.iconChunkIdsCount > 0)
|
||||||
|
@ -106,6 +116,13 @@ class IconManagerTest : KoinComponent {
|
||||||
assertTrue(output2.captured.isNotEmpty())
|
assertTrue(output2.captured.isNotEmpty())
|
||||||
|
|
||||||
assertArrayEquals(output1.captured, output2.captured)
|
assertArrayEquals(output1.captured, output2.captured)
|
||||||
|
|
||||||
|
// print compressed and uncompressed size
|
||||||
|
val size = output1.captured.size.toFloat() / 1024 / 1024
|
||||||
|
val outputStream = ByteArrayOutputStream()
|
||||||
|
ZstdOutputStream(outputStream).use { it.write(output1.captured) }
|
||||||
|
val compressedSize = outputStream.size().toFloat() / 1024 / 1024
|
||||||
|
println("Icon size: $size MB, compressed $compressedSize MB")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
package com.stevesoltys.seedvault.worker
|
package com.stevesoltys.seedvault.worker
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap.CompressFormat.JPEG
|
import android.graphics.Bitmap.CompressFormat.PNG
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -40,8 +40,7 @@ import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import java.util.zip.ZipOutputStream
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
private const val ICON_SIZE = 128
|
private const val ICON_SIZE = 64
|
||||||
private const val ICON_QUALITY = 75
|
|
||||||
private const val CACHE_FOLDER = "restore-icons"
|
private const val CACHE_FOLDER = "restore-icons"
|
||||||
private val TAG = IconManager::class.simpleName
|
private val TAG = IconManager::class.simpleName
|
||||||
|
|
||||||
|
@ -75,8 +74,10 @@ internal class IconManager(
|
||||||
setLastModifiedTime(FileTime.fromMillis(0))
|
setLastModifiedTime(FileTime.fromMillis(0))
|
||||||
}
|
}
|
||||||
zip.putNextEntry(entry)
|
zip.putNextEntry(entry)
|
||||||
// WEBP_LOSSY compression wasn't deterministic in our tests, so use JPEG
|
// WEBP_LOSSY compression wasn't deterministic in our tests,
|
||||||
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(JPEG, ICON_QUALITY, zip)
|
// and JPEG doesn't support transparency (causing black squares),
|
||||||
|
// so use PNG
|
||||||
|
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(PNG, 0, zip)
|
||||||
entries.add(it.packageName)
|
entries.add(it.packageName)
|
||||||
zip.closeEntry()
|
zip.closeEntry()
|
||||||
}
|
}
|
||||||
|
@ -91,8 +92,8 @@ internal class IconManager(
|
||||||
setLastModifiedTime(FileTime.fromMillis(0))
|
setLastModifiedTime(FileTime.fromMillis(0))
|
||||||
}
|
}
|
||||||
zip.putNextEntry(entry)
|
zip.putNextEntry(entry)
|
||||||
// WEBP_LOSSY compression wasn't deterministic in our tests, so use JPEG
|
// For PNG choice see comment above
|
||||||
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(JPEG, ICON_QUALITY, zip)
|
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(PNG, 0, zip)
|
||||||
zip.closeEntry()
|
zip.closeEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue