Created
August 20, 2023 10:38
-
-
Save rock3r/b3823998391b562a6b092251575144f8 to your computer and use it in GitHub Desktop.
Draw text on a bitmap
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
@OptIn(ExperimentalAnimationApi::class) | |
@Composable | |
private fun DrawText(it: PaddingValues) { | |
Column(Modifier.padding(it)) { | |
var text by remember { mutableStateOf("Vel eum voluptatem nulla. Ut enim unde sit autem laboriosam consequatur ut. Quo eius veniam occaecati minima. Porro architecto et omnis. Et dolor qui non. Tempora et consequuntur ea quia iste qui ducimus cum.\n") } | |
OutlinedTextField(value = text, onValueChange = { text = it.trim() }) | |
val baseFontSizePx = with(LocalDensity.current) { 24.sp.toPx() } | |
val context = LocalContext.current | |
var bitmap by remember { mutableStateOf<ImageBitmap?>(null) } | |
LaunchedEffect(key1 = text) { | |
bitmap = null | |
launch { | |
val baseDrawable = ResourcesCompat.getDrawable(context.resources, R.drawable.myImage, context.theme) | |
as? BitmapDrawable ?: error("Damnit") | |
val bitmapWithText = baseDrawable.bitmap.drawTextOnTop(text, baseFontSizePx, context.resources) | |
bitmap = bitmapWithText.asImageBitmap() | |
} | |
} | |
Spacer(modifier = Modifier.weight(1f)) | |
AnimatedContent(targetState = bitmap, label = "My thing") { imageBitmap -> | |
if (imageBitmap == null) { | |
Box( | |
modifier = Modifier | |
.fillMaxWidth() | |
.height(100.dp), contentAlignment = Alignment.Center | |
) { | |
CircularProgressIndicator() | |
} | |
} else { | |
Image(painter = BitmapPainter(imageBitmap), contentDescription = text) | |
} | |
} | |
} | |
} | |
private fun Bitmap.drawTextOnTop(text: String, textSize: Float, resources: Resources): Bitmap = | |
drawTextOnBitmap(this, text, textSize, Color.White, resources.getFont(R.font.pacifico)) | |
?: this | |
private fun drawTextOnBitmap(bitmap: Bitmap, text: String, textSize: Float, textColor: Color, typeface: android.graphics.Typeface): Bitmap? { | |
if (textSize <= 0f) { | |
Timber.tag("DrawText").e("Text is too big to fit") | |
return null | |
} | |
val paint = TextPaint().apply { | |
this.textSize = textSize | |
this.color = textColor.toArgb() | |
this.typeface = typeface | |
this.style = Paint.Style.FILL | |
} | |
val availableWidth = bitmap.width * .9f // 10% (5% + 5%) padding | |
val layout = StaticLayout.Builder.obtain(text, 0, text.length, paint, availableWidth.toInt()) | |
.setAlignment(Layout.Alignment.ALIGN_CENTER) | |
.build() | |
// Get the size of the static layout. | |
val layoutWidth = layout.width | |
val layoutHeight = layout.height | |
// Make sure that the static layout fits in the bitmap. | |
val availableHeight = bitmap.height * .9f // 10% (5% + 5%) padding | |
if (layoutWidth > availableWidth || layoutHeight > availableHeight) { | |
// The static layout is too wide. Reduce the text size. | |
return drawTextOnBitmap(bitmap, text, textSize - 1f, textColor, typeface) | |
} | |
// Draw the static layout on the bitmap. | |
val newBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true) | |
val canvas = Canvas(newBitmap) | |
canvas.withSave { | |
// Apply padding by translating to 5% of width and height before drawing | |
translate(bitmap.width * .05f, bitmap.height * .05f) | |
layout.draw(canvas) | |
} | |
return newBitmap | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment