You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas.drawText()在不同尺寸Bitmap上绘制文字大小不一致如何解决

问题描述

我正在使用Canvas API的drawText()方法在Bitmap*(图片转换得到的Bitmap)*上绘制文字,已经可以成功在Bitmap上绘制文字,但一直无法解决以下问题:
如果是设备相机拍摄的图片,叠加绘制的文字大小正常;但如果从图库中选择任意一张其他图片,叠加绘制的文字就会过大。

以下是Canvas绘制文字的相关代码:

val scale = context?.resources?.displayMetrics?.density
val textSizeInPixels = 44f

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
              style = Paint.Style.FILL
              color = Color.WHITE
              setShadowLayer(1f, 0f, 1f, Color.WHITE)
              textSize = textSizeInPixels * (scale ?: 1F)
           }

val bounds = Rect()
paint.getTextBounds(textToDraw, 0, textToDraw.length, bounds)


//imagePath是相机拍摄或图库选择的图片路径
val bitmap = BitmapFactory.decodeStream(FileInputStream(File(imagePath)))
val x = bitmap.width.minus(bitmap.width.times(widthScale)) 
val y = bitmap.height.minus(bitmap.height.times(heightScale))

canvas.drawText(textToDraw, x, y, paint)

经过调试发现,相机拍摄的图片尺寸为2176x3264 像素,在该尺寸图片上Canvas绘制的文字大小正常;而从图库选中的测试图片尺寸为914x1624 像素,在该图上绘制的文字尺寸明显过大。

核心问题

我该如何保证无论图片尺寸如何,绘制的文字大小始终保持一致?
我需要不同来源的两张图片上绘制的文字大小完全相同。

效果说明

  • 设备相机拍摄的图片,绘制文字大小正常
  • 图库选中的图片,绘制文字过大

布局代码

以下是用来展示Bitmap的ImageView对应的XML布局代码:

<com.google.android.material.card.MaterialCardView
        android:id="@+id/cv_share_img"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dimen_0"
        android:layout_marginStart="@dimen/dimen_20"
        android:layout_marginTop="@dimen/dimen_20"
        android:layout_marginEnd="@dimen/dimen_20"
        app:cardCornerRadius="@dimen/dimen_20"
        app:layout_constraintDimensionRatio="H,9:16"
        app:layout_constraintTop_toBottomOf="@id/iv_close">

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/iv_share_img"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="fitCenter" />

</com.google.android.material.card.MaterialCardView>

解决方案

问题原因

当前的文字大小是基于屏幕密度计算的固定像素值,不会随Bitmap的尺寸变化调整。高分辨率的相机图片总像素多,固定像素的文字占比小,看起来大小正常;低分辨率的图库图片总像素少,同样像素大小的文字占比就会大很多,最终显示在相同大小的ImageView里时,就会出现图库图片文字过大的问题。

解决方法

提供两种可行方案,按需选择即可:

方案1:按图片尺寸比例动态计算文字大小

以正常显示的相机图片为基准,计算出合理的文字大小和图片高度的比例,后续所有图片都用这个比例计算文字大小:

// 基准比例可根据实际显示效果调整,示例值基于相机图高度3264px、正常文字大小88px计算得到88/3264≈0.027
val TEXT_HEIGHT_RATIO = 0.027f 

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    style = Paint.Style.FILL
    color = Color.WHITE
    setShadowLayer(1f, 0f, 1f, Color.WHITE)
    // 用当前Bitmap的高度乘以比例得到适配的文字大小
    textSize = bitmap.height * TEXT_HEIGHT_RATIO
}

方案2:先统一缩放Bitmap到目标尺寸再绘制

你的ImageView尺寸是固定9:16比例的,可以先把所有加载的Bitmap统一缩放到和ImageView的实际像素大小一致,再在缩放后的Bitmap上绘制固定大小的文字,这样不管原图多大,绘制出来的文字大小完全一致:

// 先获取ImageView的实际尺寸(可在View渲染完成后通过view.post{}获取)
val targetWidth = iv_share_img.width
val targetHeight = iv_share_img.height

// 把原图缩放成目标尺寸
val scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, targetWidth, targetHeight, true)

// 之后在scaledBitmap对应的Canvas上绘制文字,textSize用原有固定值即可
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    style = Paint.Style.FILL
    color = Color.WHITE
    setShadowLayer(1f, 0f, 1f, Color.WHITE)
    textSize = 44f * (scale ?: 1F)
}

内容的提问来源于stack exchange,提问作者iCantC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 11:06:04