Skip to content

Commit

Permalink
Encode icons in PNG, because JPEG doesn't support transparency
Browse files Browse the repository at this point in the history
This caused black squares around icons.
  • Loading branch information
grote committed Oct 7, 2024
1 parent d2daf25 commit 715fa6c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@

package com.stevesoltys.seedvault.worker

import android.content.pm.PackageInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry
import com.github.luben.zstd.ZstdOutputStream
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.repo.AppBackupManager
import com.stevesoltys.seedvault.repo.BackupData
Expand All @@ -32,6 +36,7 @@ import org.junit.runner.RunWith
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import kotlin.random.Random

@RunWith(AndroidJUnit4::class)
Expand Down Expand Up @@ -76,6 +81,11 @@ class IconManagerTest : KoinComponent {
iconManager.uploadIcons()
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
val snapshot = snapshotCreator.finalizeSnapshot()
assertTrue(snapshot.iconChunkIdsCount > 0)
Expand Down Expand Up @@ -106,6 +116,13 @@ class IconManagerTest : KoinComponent {
assertTrue(output2.captured.isNotEmpty())

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")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package com.stevesoltys.seedvault.worker

import android.content.Context
import android.graphics.Bitmap.CompressFormat.JPEG
import android.graphics.Bitmap.CompressFormat.PNG
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.util.Log
Expand Down Expand Up @@ -40,8 +40,7 @@ import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream

private const val ICON_SIZE = 128
private const val ICON_QUALITY = 75
private const val ICON_SIZE = 64
private const val CACHE_FOLDER = "restore-icons"
private val TAG = IconManager::class.simpleName

Expand Down Expand Up @@ -75,8 +74,10 @@ internal class IconManager(
setLastModifiedTime(FileTime.fromMillis(0))
}
zip.putNextEntry(entry)
// WEBP_LOSSY compression wasn't deterministic in our tests, so use JPEG
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(JPEG, ICON_QUALITY, zip)
// WEBP_LOSSY compression wasn't deterministic in our tests,
// 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)
zip.closeEntry()
}
Expand All @@ -91,8 +92,8 @@ internal class IconManager(
setLastModifiedTime(FileTime.fromMillis(0))
}
zip.putNextEntry(entry)
// WEBP_LOSSY compression wasn't deterministic in our tests, so use JPEG
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(JPEG, ICON_QUALITY, zip)
// For PNG choice see comment above
drawable.toBitmap(ICON_SIZE, ICON_SIZE).compress(PNG, 0, zip)
zip.closeEntry()
}
}
Expand Down

0 comments on commit 715fa6c

Please sign in to comment.