Search code examples
androiddrawingandroid-canvas

Canvas Drawing Small Text


I am trying to draw text on bitmap but text size differs in different pictures. Text size keeps is too small on some bitmaps and large on some. I have noticed that it is small on big resolution bitmaps. This is how I'm trying to draw. Please tell what I'm doing wrong

val originalBitmap = MediaStore.Images.Media.getBitmap(
        context.contentResolver,
        uri
    )
    val bitmap = convertToMutable(
        originalBitmap
    )
    val ratio = originalBitmap.width/bitmap.width
    val scale = context.resources.displayMetrics.density
    val canvas = Canvas(bitmap)

    val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
    textPaint.color = Color.WHITE
    textPaint.textSize = 7f * scale
    textPaint.style = Paint.Style.FILL

    val locBound = Rect()
    textPaint.getTextBounds(location,0,location.length,locBound)

    val txtWidth = (canvas.width - 15)
    val txtHeight = textPaint.measureText("yY")

    val txtTopX = ((bitmap.width - txtWidth) - 15).toFloat()
    val txtTopY = ((bitmap.height - txtHeight) - 20).toFloat()

    canvas.drawMultilineText(
        location,
        textPaint,
        txtWidth,
        txtTopX,
        txtTopY,
        0,
        location.length,
        Layout.Alignment.ALIGN_OPPOSITE
    )`
fun Canvas.drawMultilineText(
    text: CharSequence,
    textPaint: TextPaint,
    width: Int,
    x: Float,
    y: Float,
    start: Int = 0,
    end: Int = text.length,
    alignment: Layout.Alignment = Layout.Alignment.ALIGN_NORMAL,
    spacingMult: Float = 1f,
    spacingAdd: Float = 0f,
    includePad: Boolean = true,
    ellipsizedWidth: Int = width,
    ellipsize: TextUtils.TruncateAt? = null
) {

    val cacheKey = "$text-$start-$end-$textPaint-$width-$alignment-" +
            "$spacingMult-$spacingAdd-$includePad-$ellipsizedWidth-$ellipsize"

    // The public constructor was deprecated in API level 28,
    // but the builder is only available from API level 23 onwards
    val staticLayout =
        StaticLayoutCache[cacheKey] ?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            StaticLayout.Builder.obtain(text, start, end, textPaint, width)
                .setAlignment(alignment)
                .setLineSpacing(spacingAdd, spacingMult)
                .setIncludePad(includePad)
                .setEllipsizedWidth(ellipsizedWidth)
                .setEllipsize(ellipsize)
                .build()
        } else {
            StaticLayout(
                text, start, end, textPaint, width, alignment,
                spacingMult, spacingAdd, includePad, ellipsize, ellipsizedWidth
            )
                .apply { StaticLayoutCache[cacheKey] = this }
        }

    staticLayout.draw(this, x, y)
}

Here is the result I'm getting First Image Second Image Third Image


Solution

  • You can set font size based on your image size. for example your font size can be 0.03 of image size. So in this way your font size on image can be change base on your image size. so you need to do this as bellow:

    var imageSize = max(originalBitmap.width, originalBitmap.height)
    var fontScale = 0.03
    var textSize = imageSize * fontScale  
    textPaint.textSize = textSize
    

    You must note that image can be landscape or portrait. so we get width or height that is greater as imageSize. You can change fontScale according to your needs.

    Also, I think there is no need to use scale variable in textSize computing. because it is a display metric and can be different in various devices, so must not be affected in bitmap text size, and text size must only define based on bitmap image size.