Last active
August 15, 2021 10:57
-
-
Save frel/1cbb5404f33db69e0b91fda18feb45a2 to your computer and use it in GitHub Desktop.
AirBrush Medium article example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TinyThumbDecoder( | |
private var context: Context, | |
private val bitmapPool: BitmapPool, | |
private val blurProvider: (source: Bitmap, options: BlurOptions?) -> Bitmap | |
) : ResourceDecoder<TinyThumb, BitmapDrawable> { | |
override fun handles(source: TinyThumb, options: Options) = source.base64.isNotEmpty() | |
override fun decode( | |
source: TinyThumb, | |
width: Int, | |
height: Int, | |
options: Options | |
): Resource<BitmapDrawable>? { | |
// Down sample the blurred bitmap to save resources. | |
// The later hardware upscale will look almost identical anyway. | |
val sampleSize = source.options?.sampleSize?.coerceAtLeast(1) ?: 6 | |
val bitmap = generateBitmap(source, width / sampleSize, height / sampleSize) | |
val bitmapResource = BitmapResource.obtain(bitmap, bitmapPool) | |
return LazyBitmapDrawableResource.obtain(context.resources, bitmapResource) | |
} | |
private fun generateBitmap(thumb: TinyThumb, width: Int, height: Int): Bitmap { | |
// This is application specific and must match how it was encoded | |
val decodeFlag = Base64.URL_SAFE | |
val bytes = Base64.decode(thumb.base64, decodeFlag) | |
val options = BitmapFactory.Options().apply { | |
// RGB565 will take less memory, but the resulting gradient is horrible. | |
inPreferredConfig = Bitmap.Config.ARGB_8888 | |
} | |
// Convert the byte array into a bitmap. | |
val source = requireNotNull(BitmapFactory.decodeByteArray(bytes, 0, bytes.size, options)) { | |
"Failed to decode byte array. This can happen if the decode flag does not match the flag the data was encoded with." | |
} | |
// If the thumb is square or landscape, center crop it. Otherwise leave it as is. | |
val centerCrop = crop(source, width, height, 0.5f, 1f) | |
return blurProvider(centerCrop, thumb.options).also { centerCrop.recycle() } | |
} | |
/** | |
* Returns a new Bitmap (from the pool) with a crop effect depending on the crop anchor given. | |
* 0.5f is like [android.widget.ImageView.ScaleType.CENTER_CROP]. The crop anchor will be be nudged | |
* so the entire cropped bitmap will fit inside the src. May return the input bitmap if no | |
* scaling is necessary. | |
*/ | |
private fun crop( | |
source: Bitmap, | |
width: Int, | |
height: Int, | |
horizontalCenterPercent: Float, | |
verticalCenterPercent: Float | |
): Bitmap = TODO("Beyond the scope of this article") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment