添加拼图底部标题和内容区域
This commit is contained in:
@@ -365,20 +365,12 @@ fun MergeScreen(
|
|||||||
context,
|
context,
|
||||||
imageItems,
|
imageItems,
|
||||||
layoutType,
|
layoutType,
|
||||||
imageQuality
|
imageQuality,
|
||||||
).let { bitmap ->
|
|
||||||
if (title.isNotBlank() || content.isNotBlank()) {
|
|
||||||
ImageProcessor.addTextToBitmap(
|
|
||||||
bitmap,
|
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
titleStyle,
|
titleStyle,
|
||||||
contentStyle
|
contentStyle
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
bitmap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
showPreview = true
|
showPreview = true
|
||||||
}
|
}
|
||||||
@@ -439,20 +431,12 @@ fun MergeScreen(
|
|||||||
context,
|
context,
|
||||||
imageItems,
|
imageItems,
|
||||||
layoutType,
|
layoutType,
|
||||||
imageQuality
|
imageQuality,
|
||||||
).let { mergedBitmap ->
|
|
||||||
if (title.isNotBlank() || content.isNotBlank()) {
|
|
||||||
ImageProcessor.addTextToBitmap(
|
|
||||||
mergedBitmap,
|
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
titleStyle,
|
titleStyle,
|
||||||
contentStyle
|
contentStyle
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
mergedBitmap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val fileName = ImageProcessor.generateFileName(title.ifBlank { "合成" })
|
val fileName = ImageProcessor.generateFileName(title.ifBlank { "合成" })
|
||||||
|
|||||||
@@ -155,9 +155,13 @@ object ImageProcessor {
|
|||||||
context: Context,
|
context: Context,
|
||||||
images: List<ImageItem>,
|
images: List<ImageItem>,
|
||||||
layoutType: MergeLayoutType,
|
layoutType: MergeLayoutType,
|
||||||
quality: ImageQuality
|
quality: ImageQuality,
|
||||||
|
title: String = "",
|
||||||
|
content: String = "",
|
||||||
|
titleStyle: WatermarkStyle = WatermarkStyle.Default,
|
||||||
|
contentStyle: WatermarkStyle = WatermarkStyle.Default
|
||||||
): Bitmap {
|
): Bitmap {
|
||||||
if (images.isEmpty()) {
|
if (images.isEmpty() && title.isBlank() && content.isBlank()) {
|
||||||
return Bitmap.createBitmap(1920, 1080, Bitmap.Config.ARGB_8888)
|
return Bitmap.createBitmap(1920, 1080, Bitmap.Config.ARGB_8888)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +169,20 @@ object ImageProcessor {
|
|||||||
val rows = layoutType.rows
|
val rows = layoutType.rows
|
||||||
|
|
||||||
val outputWidth = 1920
|
val outputWidth = 1920
|
||||||
val outputHeight = 1080
|
|
||||||
val cellWidth = outputWidth / cols
|
val cellWidth = outputWidth / cols
|
||||||
val cellHeight = outputHeight / rows
|
val cellHeight = outputWidth / cols // 保持正方形格子
|
||||||
|
|
||||||
|
// 底部文字区域高度
|
||||||
|
val textAreaHeight = if (title.isNotBlank() || content.isNotBlank()) {
|
||||||
|
200 // 200像素高度的文字区域
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片区域高度
|
||||||
|
val imageAreaHeight = cellHeight * rows
|
||||||
|
|
||||||
|
val outputHeight = imageAreaHeight + textAreaHeight
|
||||||
|
|
||||||
val result = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888)
|
val result = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888)
|
||||||
val canvas = Canvas(result)
|
val canvas = Canvas(result)
|
||||||
@@ -175,6 +190,7 @@ object ImageProcessor {
|
|||||||
|
|
||||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||||
|
|
||||||
|
// 绘制图片网格
|
||||||
images.forEachIndexed { index, imageItem ->
|
images.forEachIndexed { index, imageItem ->
|
||||||
if (index >= rows * cols) return@forEachIndexed
|
if (index >= rows * cols) return@forEachIndexed
|
||||||
|
|
||||||
@@ -208,6 +224,97 @@ object ImageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 绘制底部文字区域
|
||||||
|
if (textAreaHeight > 0) {
|
||||||
|
val textTop = imageAreaHeight
|
||||||
|
|
||||||
|
// 绘制白色背景
|
||||||
|
canvas.drawRect(
|
||||||
|
0f, textTop.toFloat(),
|
||||||
|
outputWidth.toFloat(), outputHeight.toFloat(),
|
||||||
|
Paint().apply { color = Color.WHITE }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 绘制分割线
|
||||||
|
canvas.drawLine(
|
||||||
|
0f, textTop.toFloat(),
|
||||||
|
outputWidth.toFloat(), textTop.toFloat(),
|
||||||
|
Paint().apply {
|
||||||
|
color = Color.LTGRAY
|
||||||
|
strokeWidth = 2f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 绘制标题
|
||||||
|
if (title.isNotBlank()) {
|
||||||
|
val titlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
|
textSize = titleStyle.fontSize * 2f // 放大标题
|
||||||
|
color = titleStyle.textColor.toArgb()
|
||||||
|
typeface = Typeface.DEFAULT_BOLD
|
||||||
|
textAlign = Paint.Align.CENTER
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题背景
|
||||||
|
val titleBgPaint = Paint().apply {
|
||||||
|
color = titleStyle.backgroundColor.toArgb()
|
||||||
|
}
|
||||||
|
val titleWidth = titlePaint.measureText(title)
|
||||||
|
val titleHeight = titlePaint.fontMetrics.let { it.descent - it.ascent }
|
||||||
|
val titleBgRect = RectF(
|
||||||
|
(outputWidth - titleWidth) / 2 - 20,
|
||||||
|
textTop + 20f,
|
||||||
|
(outputWidth + titleWidth) / 2 + 20,
|
||||||
|
textTop + 20f + titleHeight + 20
|
||||||
|
)
|
||||||
|
canvas.drawRoundRect(titleBgRect, 8f, 8f, titleBgPaint)
|
||||||
|
|
||||||
|
// 标题文字
|
||||||
|
canvas.drawText(title, outputWidth / 2f, textTop + 20f + titleHeight, titlePaint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制内容
|
||||||
|
if (content.isNotBlank()) {
|
||||||
|
val contentPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
|
textSize = contentStyle.fontSize * 1.5f // 放大内容
|
||||||
|
color = contentStyle.textColor.toArgb()
|
||||||
|
typeface = Typeface.DEFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
val padding = 40f
|
||||||
|
val contentMaxWidth = outputWidth - padding * 2
|
||||||
|
val contentLines = wrapText(content, contentPaint, contentMaxWidth)
|
||||||
|
val lineHeight = contentPaint.fontMetrics.let { it.descent - it.ascent }
|
||||||
|
|
||||||
|
// 内容背景
|
||||||
|
val contentBgPaint = Paint().apply {
|
||||||
|
color = contentStyle.backgroundColor.toArgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从标题下方开始绘制内容
|
||||||
|
val contentStartY = if (title.isNotBlank()) {
|
||||||
|
textTop + 80f + lineHeight
|
||||||
|
} else {
|
||||||
|
textTop + 20f + lineHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
val totalContentHeight = contentLines.size * lineHeight + 20
|
||||||
|
val contentBgRect = RectF(
|
||||||
|
padding - 10,
|
||||||
|
contentStartY - lineHeight - 10,
|
||||||
|
outputWidth - padding + 10,
|
||||||
|
contentStartY + totalContentHeight
|
||||||
|
)
|
||||||
|
canvas.drawRoundRect(contentBgRect, 8f, 8f, contentBgPaint)
|
||||||
|
|
||||||
|
// 内容文字
|
||||||
|
var y = contentStartY
|
||||||
|
contentLines.forEach { line ->
|
||||||
|
canvas.drawText(line, padding, y, contentPaint)
|
||||||
|
y += lineHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user