调整拼图内容区域起始位置
This commit is contained in:
@@ -30,7 +30,7 @@ import java.util.Locale
|
|||||||
*/
|
*/
|
||||||
object ImageProcessor {
|
object ImageProcessor {
|
||||||
|
|
||||||
private val dateFormat = SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss", Locale.getDefault())
|
private val dateFormat = SimpleDateFormat("yyyy年M月d日 HH:mm:ss", Locale.getDefault())
|
||||||
private val fileNameFormat = SimpleDateFormat("yyyyMMddHHmm", Locale.getDefault())
|
private val fileNameFormat = SimpleDateFormat("yyyyMMddHHmm", Locale.getDefault())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,6 +92,7 @@ object ImageProcessor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加水印到图片
|
* 添加水印到图片
|
||||||
|
* 右下角半透明白色文字,带黑色描边/阴影,高质感摄影风格
|
||||||
*/
|
*/
|
||||||
fun addWatermark(
|
fun addWatermark(
|
||||||
sourceBitmap: Bitmap,
|
sourceBitmap: Bitmap,
|
||||||
@@ -99,51 +100,54 @@ object ImageProcessor {
|
|||||||
locationText: String,
|
locationText: String,
|
||||||
style: WatermarkStyle
|
style: WatermarkStyle
|
||||||
): Bitmap {
|
): Bitmap {
|
||||||
android.util.Log.d("ImageProcessor", "addWatermark called, timeText=$timeText, locationText=$locationText")
|
|
||||||
|
|
||||||
val result = sourceBitmap.copy(Bitmap.Config.ARGB_8888, true)
|
val result = sourceBitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||||
val canvas = Canvas(result)
|
val canvas = Canvas(result)
|
||||||
|
|
||||||
// 使用固定的字体大小,基于图片宽度比例
|
// 字体大小:图片宽度的1/40,现代简洁字体
|
||||||
val baseFontSize = result.width / 40f // 字体大小为图片宽度的1/40
|
val baseFontSize = result.width / 40f
|
||||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
val lineHeight = baseFontSize * 1.3f
|
||||||
textSize = baseFontSize
|
|
||||||
color = style.textColor.toArgb()
|
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
|
||||||
textAlign = Paint.Align.CENTER
|
|
||||||
}
|
|
||||||
|
|
||||||
val watermarkText = "$timeText $locationText"
|
|
||||||
val textWidth = paint.measureText(watermarkText)
|
|
||||||
val textHeight = paint.fontMetrics.let { it.descent - it.ascent }
|
|
||||||
|
|
||||||
android.util.Log.d("ImageProcessor", "Watermark: width=$textWidth, height=$textHeight, text=$watermarkText")
|
// 位置:右下角
|
||||||
|
val padding = result.width / 30f
|
||||||
// 计算位置(底部中央)
|
val x = result.width - padding
|
||||||
val padding = result.width / 30f // 边距为图片宽度的1/30
|
|
||||||
val x = result.width / 2f
|
|
||||||
val y = result.height - padding
|
val y = result.height - padding
|
||||||
|
|
||||||
// 绘制背景
|
// 绘制水印文字 - 先绘制阴影/描边,再绘制主文字
|
||||||
val bgColorInt = style.backgroundColor.toArgb()
|
fun drawTextWithShadow(text: String, textY: Float) {
|
||||||
android.util.Log.d("ImageProcessor", "Background color int: $bgColorInt")
|
// 绘制阴影(向右下偏移)
|
||||||
if (bgColorInt != 0) {
|
val shadowPaint = android.graphics.Paint().apply {
|
||||||
val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
isAntiAlias = true
|
||||||
color = bgColorInt
|
textSize = baseFontSize
|
||||||
|
color = android.graphics.Color.argb(120, 0, 0, 0)
|
||||||
|
typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
|
||||||
|
textAlign = android.graphics.Paint.Align.RIGHT
|
||||||
}
|
}
|
||||||
val bgRect = RectF(
|
canvas.drawText(text, x + 1.5f, textY + 1.5f, shadowPaint)
|
||||||
x - textWidth / 2 - padding / 2,
|
|
||||||
y - textHeight - padding / 2,
|
// 绘制主文字 - 半透明白色
|
||||||
x + textWidth / 2 + padding / 2,
|
val textPaint = android.graphics.Paint().apply {
|
||||||
y + padding / 2
|
isAntiAlias = true
|
||||||
)
|
textSize = baseFontSize
|
||||||
canvas.drawRoundRect(bgRect, 8f, 8f, bgPaint)
|
color = android.graphics.Color.argb(230, 255, 255, 255)
|
||||||
android.util.Log.d("ImageProcessor", "Background drawn at x=$x, y=$y")
|
typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
|
||||||
|
textAlign = android.graphics.Paint.Align.RIGHT
|
||||||
|
}
|
||||||
|
canvas.drawText(text, x, textY, textPaint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制文字
|
// 绘制水印
|
||||||
canvas.drawText(watermarkText, x, y, paint)
|
if (timeText.isNotBlank()) {
|
||||||
android.util.Log.d("ImageProcessor", "Text drawn at x=$x, y=$y")
|
// 时间行
|
||||||
|
drawTextWithShadow(timeText, y)
|
||||||
|
|
||||||
|
// 位置行(在时间上方)
|
||||||
|
if (locationText.isNotBlank()) {
|
||||||
|
drawTextWithShadow(locationText, y - lineHeight - 8)
|
||||||
|
}
|
||||||
|
} else if (locationText.isNotBlank()) {
|
||||||
|
// 只有位置信息
|
||||||
|
drawTextWithShadow(locationText, y)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -169,8 +173,9 @@ object ImageProcessor {
|
|||||||
val rows = layoutType.rows
|
val rows = layoutType.rows
|
||||||
|
|
||||||
val outputWidth = 1920
|
val outputWidth = 1920
|
||||||
val cellWidth = outputWidth / cols
|
val cellSpacing = 16 // 单元格间距 16px (约 4dp * 4)
|
||||||
val cellHeight = outputWidth / cols // 保持正方形格子
|
val cellWidth = (outputWidth - cellSpacing * (cols + 1)) / cols
|
||||||
|
val cellHeight = cellWidth // 保持正方形格子
|
||||||
|
|
||||||
// 底部文字区域高度
|
// 底部文字区域高度
|
||||||
val textAreaHeight = if (title.isNotBlank() || content.isNotBlank()) {
|
val textAreaHeight = if (title.isNotBlank() || content.isNotBlank()) {
|
||||||
@@ -180,7 +185,7 @@ object ImageProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 图片区域高度
|
// 图片区域高度
|
||||||
val imageAreaHeight = cellHeight * rows
|
val imageAreaHeight = cellHeight * rows + cellSpacing * (rows + 1)
|
||||||
|
|
||||||
val outputHeight = imageAreaHeight + textAreaHeight
|
val outputHeight = imageAreaHeight + textAreaHeight
|
||||||
|
|
||||||
@@ -197,8 +202,8 @@ object ImageProcessor {
|
|||||||
val col = index % cols
|
val col = index % cols
|
||||||
val row = index / cols
|
val row = index / cols
|
||||||
|
|
||||||
val left = col * cellWidth
|
val left = cellSpacing + col * (cellWidth + cellSpacing)
|
||||||
val top = row * cellHeight
|
val top = cellSpacing + row * (cellHeight + cellSpacing)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val sourceBitmap = tryLoadBitmap(context, imageItem)
|
val sourceBitmap = tryLoadBitmap(context, imageItem)
|
||||||
@@ -228,85 +233,53 @@ object ImageProcessor {
|
|||||||
if (textAreaHeight > 0) {
|
if (textAreaHeight > 0) {
|
||||||
val textTop = imageAreaHeight
|
val textTop = imageAreaHeight
|
||||||
|
|
||||||
// 绘制白色背景
|
// 绘制统一的深灰色背景
|
||||||
|
val bgColor = android.graphics.Color.argb(255, 60, 60, 60) // 深灰色
|
||||||
canvas.drawRect(
|
canvas.drawRect(
|
||||||
0f, textTop.toFloat(),
|
0f, textTop.toFloat(),
|
||||||
outputWidth.toFloat(), outputHeight.toFloat(),
|
outputWidth.toFloat(), outputHeight.toFloat(),
|
||||||
Paint().apply { color = Color.WHITE }
|
Paint().apply { color = bgColor }
|
||||||
)
|
)
|
||||||
|
|
||||||
// 绘制分割线
|
val padding = 30f
|
||||||
canvas.drawLine(
|
val titleHeight: Float
|
||||||
0f, textTop.toFloat(),
|
|
||||||
outputWidth.toFloat(), textTop.toFloat(),
|
|
||||||
Paint().apply {
|
|
||||||
color = Color.LTGRAY
|
|
||||||
strokeWidth = 2f
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 绘制标题
|
// 绘制标题 - 粗体白色居中
|
||||||
if (title.isNotBlank()) {
|
if (title.isNotBlank()) {
|
||||||
val titlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
val titlePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
textSize = titleStyle.fontSize * 2f // 放大标题
|
textSize = outputWidth / 25f
|
||||||
color = titleStyle.textColor.toArgb()
|
color = android.graphics.Color.WHITE
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
typeface = Typeface.create("sans-serif", Typeface.BOLD) // 粗体无衬线
|
||||||
textAlign = Paint.Align.CENTER
|
textAlign = android.graphics.Paint.Align.CENTER
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标题背景
|
titleHeight = titlePaint.fontMetrics.let { it.descent - it.ascent }
|
||||||
val titleBgPaint = Paint().apply {
|
canvas.drawText(title, outputWidth / 2f, textTop + padding + titleHeight, titlePaint)
|
||||||
color = titleStyle.backgroundColor.toArgb()
|
} else {
|
||||||
}
|
titleHeight = 0f
|
||||||
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()) {
|
if (content.isNotBlank()) {
|
||||||
val contentPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
val contentPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
textSize = contentStyle.fontSize * 1.5f // 放大内容
|
textSize = outputWidth / 35f
|
||||||
color = contentStyle.textColor.toArgb()
|
color = android.graphics.Color.WHITE
|
||||||
typeface = Typeface.DEFAULT
|
typeface = Typeface.create("sans-serif", Typeface.NORMAL) // 细体
|
||||||
|
textAlign = android.graphics.Paint.Align.LEFT
|
||||||
}
|
}
|
||||||
|
|
||||||
val padding = 40f
|
|
||||||
val contentMaxWidth = outputWidth - padding * 2
|
val contentMaxWidth = outputWidth - padding * 2
|
||||||
val contentLines = wrapText(content, contentPaint, contentMaxWidth)
|
val contentLines = wrapText(content, contentPaint, contentMaxWidth)
|
||||||
val lineHeight = contentPaint.fontMetrics.let { it.descent - it.ascent }
|
val lineHeight = contentPaint.fontMetrics.let { it.descent - it.ascent }
|
||||||
|
|
||||||
// 内容背景
|
// 内容起始Y坐标 - 标题下方再往下移一行
|
||||||
val contentBgPaint = Paint().apply {
|
|
||||||
color = contentStyle.backgroundColor.toArgb()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从标题下方开始绘制内容
|
|
||||||
val contentStartY = if (title.isNotBlank()) {
|
val contentStartY = if (title.isNotBlank()) {
|
||||||
textTop + 80f + lineHeight
|
textTop + padding + titleHeight + lineHeight + 20
|
||||||
} else {
|
} else {
|
||||||
textTop + 20f + lineHeight
|
textTop + padding + lineHeight * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
var y = contentStartY
|
||||||
contentLines.forEach { line ->
|
contentLines.forEach { line ->
|
||||||
canvas.drawText(line, padding, y, contentPaint)
|
canvas.drawText(line, padding, y, contentPaint)
|
||||||
|
|||||||
Reference in New Issue
Block a user