Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.aliucord.manager.patcher.util.ArscUtil
import com.aliucord.manager.patcher.util.*
import com.aliucord.manager.patcher.util.ArscUtil.addColorResource
import com.aliucord.manager.patcher.util.ArscUtil.addResource
import com.aliucord.manager.patcher.util.ArscUtil.getMainArscChunk
import com.aliucord.manager.patcher.util.ArscUtil.getPackageChunk
import com.aliucord.manager.patcher.util.ArscUtil.getResourceFileName
import com.aliucord.manager.patcher.util.ArscUtil.getResourceFileNames
import com.aliucord.manager.patcher.util.AxmlUtil
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import com.aliucord.manager.util.getRawBytes
Expand Down Expand Up @@ -103,13 +102,17 @@ class PatchIconsStep(private val options: PatchOptions) : Step(), KoinComponent
var foregroundIcon: BinaryResourceIdentifier? = null
var backgroundIcon: BinaryResourceIdentifier? = null
var monochromeIcon: BinaryResourceIdentifier? = null
val monochromePath = when (options.iconReplacement) {
is IconReplacement.CustomImage -> "res/ic_aliucord_monochrome.png"
else -> "res/ic_aliucord_monochrome.xml"
}

// Add the monochrome resource and add the resource file later
if (isMonochromeIconsAvailable) {
container.log("Adding monochrome icon resource to arsc")

val filePathIdx = arsc.getMainArscChunk().stringPool
.addString("res/ic_aliucord_monochrome.xml")
.addString(monochromePath)

monochromeIcon = arsc.getPackageChunk().addResource(
typeName = "drawable",
Expand Down Expand Up @@ -177,14 +180,22 @@ class PatchIconsStep(private val options: PatchOptions) : Step(), KoinComponent
container.log("Writing other patched files back to apk")
ZipWriter(apk, /* append = */ true).use {
if (isMonochromeIconsAvailable) {
val monochromeIconId = if (options.iconReplacement is IconReplacement.OldDiscord) {
R.drawable.ic_discord_old_monochrome
} else {
R.drawable.ic_discord_monochrome
val monochromeBytes = when (val icon = options.iconReplacement) {
is IconReplacement.CustomImage -> {
val image = BitmapFactory.decodeStream(icon.imageBytes.inputStream())
?: error("Custom icon could not be decoded")

MonochromeMask.create(image)
.also { image.recycle() }
}

is IconReplacement.OldDiscord -> context.resources.getRawBytes(R.drawable.ic_discord_old_monochrome)

else -> context.resources.getRawBytes(R.drawable.ic_discord_monochrome)
}

container.log("Writing monochrome icon AXML to apk")
it.writeEntry("res/ic_aliucord_monochrome.xml", context.resources.getRawBytes(monochromeIconId))
container.log("Writing monochrome icon to apk at $monochromePath")
it.writeEntry(monochromePath, monochromeBytes)
}

if (options.iconReplacement is IconReplacement.OldDiscord) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.aliucord.manager.patcher.util

import android.graphics.Bitmap
import androidx.core.graphics.createBitmap
import java.io.ByteArrayOutputStream

object MonochromeMask {
/**
* Create a monochrome adaptive icon layer for a specific image.
*/
fun create(image: Bitmap): ByteArray {
val width = image.width
val height = image.height

val pixels = IntArray(width * height)
image.getPixels(pixels, 0, width, 0, 0, width, height)

val hasTransparency = pixels.any { (it ushr 24 and 0xFF) < /* transparency level = */ 250 }

pixels.forEachIndexed { i, pixel ->
val alpha = pixel ushr 24 and 0xFF
val mask = if (hasTransparency) {
alpha
} else {
luminance(pixel) * alpha / 255
}

// Only replace the colors depending on alpha
pixels[i] = (mask shl 24) or 0xFFFFFF
}

val newImage = createBitmap(width, height).apply {
setPixels(pixels, 0, width, 0, 0, width, height)
}

return ByteArrayOutputStream().use {
newImage.compress(Bitmap.CompressFormat.PNG, 100, it)
newImage.recycle()
it.toByteArray()
}
}

// Rec. 601: Perceptual brightness, the safe default for photos and most logos
private fun luminance(pixel: Int): Int {
val red = (pixel ushr 16) and 0xFF
val green = (pixel ushr 8) and 0xFF
val blue = pixel and 0xFF

return (red * 299 + green * 587 + blue * 114) / 1000
}
}
Loading