思路:

获取到图片的高度 bitmapHeight 宽度 bitmapWidth;

根据文字大小计算出图片宽度的一行可以放多少个文字 count,然后根据文字长度和 count 计算出需要几行来显示文字;

之后新建一个 Bitmap 对象,它的宽度就是图片宽度,高度是图片高度+配文与图片间的间距+文字大小文字行数+文字间的行间距文字行数;

以 Bitmap 构建画布对象,先将图片画上来,然后在图片下边画出以配文与图片间的间距+文字大小文字行数+文字间的行间距文字行数为高度的一个白底矩形,用来盛放文字(这里说一下为什么要画这个矩形,是因为我们的项目要求可以保存这张图片,而保存到相册后,手机相册背景是黑色的,我们不画这个白色矩形背景的话,文字默认背景就是透明的,而文字如果设置成黑色,这时候就会感觉你的图片只有图片没有下边的配文了,不符合要求,也不美观);

用一个循环来画出文字,返回新的图片。

代码如下:

import android.content.Context
import android.graphics.*
import com.wuc.server.ServerApplication.Companion.context
import kotlin.math.ceil
/**
* @desciption: 图片加上文字
*/
object ImageTextUtils {
/**传递进来的源图片*/
private var mBitmapSource: Bitmap? = null
/**图片的配文*/
private var mText: String? = null
/**图片加上配文后生成的新图片*/
private var mNewBitmap: Bitmap? = null
/**配文的颜色*/
private var mTextColor: Int = Color.BLACK
/**配文的字体大小*/
private var mTextSize: Float = 36f
/**图片的宽度*/
private var mBitmapWidth: Int = 0
/**图片的高度*/
private var mBitmapHeight: Int = 0
/**画图片的画笔*/
private var mBitmapPaint: Paint? = null
/**画文字的画笔*/
private var mTextPaint: Paint? = null
/**配文与图片间的距离*/
private var mPadding: Float = dp2px(10).toFloat()
/**配文行与行之间的距离*/
private var mLinePadding: Float = dp2px(15).toFloat()
init {
mBitmapPaint = Paint(Paint.ANTI_ALIAS_FLAG)
mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
}
fun drawTextToBitmap(context: Context, imgId: Int, text: String): Bitmap? {
val bitmapSource = BitmapFactory.decodeResource(context.resources, imgId)
mBitmapWidth = bitmapSource.width
mBitmapHeight = bitmapSource.height
//一行可以显示文字的个数
val lineTextCount = ((mBitmapWidth - 20) / mTextSize).toInt()
//一共要把文字分为几行
val line = ceil(text.length.toDouble() / lineTextCount.toDouble()).toInt()
//新创建一个新图片比源图片多出一部分,后续用来与文字叠加用
//宽度就是图片宽度,高度是图片高度+配文与图片间的间距+文字大小*文字行数+文字间的行间距*文字行数;
val totalHeight = mBitmapHeight + mPadding + mTextSize * line + mLinePadding * line
mNewBitmap = Bitmap.createBitmap(
mBitmapWidth,
totalHeight.toInt(),
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(mNewBitmap!!)
//把图片画上来
canvas.drawBitmap(bitmapSource, 0f, 0f, mBitmapPaint)
//在图片下边画一个白色矩形块用来放文字,防止文字是透明背景,在有些情况下保存到本地后看不出来
mTextPaint?.color = Color.WHITE
canvas.drawRect(
0f, mBitmapHeight.toFloat(), mBitmapWidth.toFloat(),
totalHeight, mTextPaint!!
)
//把文字画上来
mTextPaint?.color = mTextColor
mTextPaint?.textSize = mTextSize
val boundsRect = Rect()
//开启循环直到画完所有行的文字
for (i in 0 until line) {
val str: String = if (i == line - 1) {
text.substring(i * lineTextCount, text.length)
} else {//不是最后一行
text.substring(i * lineTextCount, (i + 1) * lineTextCount)
}
//如果是最后一行,则结束位置就是文字的长度,别下标越界哦
//获取文字的字宽高以便把文字与图片中心对齐
mTextPaint?.getTextBounds(str, 0, str.length, boundsRect)
//画文字的时候高度需要注意文字大小以及文字行间距
canvas.drawText(
str,
(mBitmapWidth / 2 - boundsRect.width() / 2).toFloat(),
mBitmapHeight + mPadding + i * mLinePadding + boundsRect.height() / 2,
mTextPaint!!
)
}
canvas.save()
canvas.restore()
return mNewBitmap
}
private fun dp2px(value: Int): Int {
val v = context.resources.displayMetrics.density
return (v * value + 0.5f).toInt()
}
private fun sp2px(value: Int): Int {
val v = context.resources.displayMetrics.scaledDensity
return (v * value + 0.5f).toInt()
}
}

在 Activity 中的使用方式:

val textToBitmap = ImageTextUtils.drawTextToBitmap(this, R.mipmap.wudang, "图片和文字结合图片和文字结合图片和文字结合图片和文字结合图片和文字结合")

image_selected.setImageBitmap(textToBitmap)