Implement 32_FIX_PRESET.md: create non-linear applyHighImpactPreset mapping for photo save, and apply to captured photo background thread processing
This commit is contained in:
@@ -1529,25 +1529,17 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Apply Current Preset Filters (ColorMatrix + Semi-transparent overlay color)
|
||||
// 3. Apply Current Preset Filters (High-Impact Color Engine)
|
||||
val preset = currentSelectedPreset ?: colorPresets[0]
|
||||
|
||||
val filteredBitmap = android.graphics.Bitmap.createBitmap(
|
||||
processedBitmap.width, processedBitmap.height, android.graphics.Bitmap.Config.ARGB_8888
|
||||
)
|
||||
val canvas = android.graphics.Canvas(filteredBitmap)
|
||||
val paint = android.graphics.Paint().apply {
|
||||
isAntiAlias = true
|
||||
isFilterBitmap = true
|
||||
val filteredBitmap = if (preset.id != "DEFAULT") {
|
||||
applyHighImpactPreset(processedBitmap, preset)
|
||||
} else {
|
||||
processedBitmap.copy(android.graphics.Bitmap.Config.ARGB_8888, true).also {
|
||||
processedBitmap.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
if (preset.id != "DEFAULT") {
|
||||
val finalMatrix = getColorMatrixForPreset(preset)
|
||||
paint.colorFilter = android.graphics.ColorMatrixColorFilter(finalMatrix)
|
||||
}
|
||||
canvas.drawBitmap(processedBitmap, 0f, 0f, paint)
|
||||
processedBitmap.recycle()
|
||||
|
||||
val canvas = android.graphics.Canvas(filteredBitmap)
|
||||
val overlayColor = getFilterColorForPreset(preset)
|
||||
if (overlayColor != android.graphics.Color.TRANSPARENT) {
|
||||
val overlayPaint = android.graphics.Paint().apply {
|
||||
@@ -1559,47 +1551,6 @@ class MainActivity : AppCompatActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
// Apply non-linear Highlights and Shadows correction
|
||||
if (preset.basic.highlight != 0f || preset.basic.shadow != 0f) {
|
||||
val width = filteredBitmap.width
|
||||
val height = filteredBitmap.height
|
||||
val pixels = IntArray(width * height)
|
||||
filteredBitmap.getPixels(pixels, 0, width, 0, 0, width, height)
|
||||
|
||||
val highlightVal = preset.basic.highlight
|
||||
val shadowVal = preset.basic.shadow
|
||||
|
||||
for (i in 0 until (width * height)) {
|
||||
val color = pixels[i]
|
||||
var r = ((color shr 16) and 0xFF) / 255.0f
|
||||
var g = ((color shr 8) and 0xFF) / 255.0f
|
||||
var b = (color and 0xFF) / 255.0f
|
||||
|
||||
val luminance = 0.2126f * r + 0.7152f * g + 0.0722f * b
|
||||
|
||||
if (luminance > 0.6f) {
|
||||
// Vùng sáng (Highlight): Tăng/Giảm độ sáng dựa trên thông số highlight của Preset
|
||||
val weight = (luminance - 0.6f) / 0.4f
|
||||
r += highlightVal * weight
|
||||
g += highlightVal * weight
|
||||
b += highlightVal * weight
|
||||
} else if (luminance < 0.4f) {
|
||||
// Vùng tối (Shadow): Bù sáng hoặc dìm tối dựa trên thông số shadow của Preset
|
||||
val weight = (0.4f - luminance) / 0.4f
|
||||
r += shadowVal * weight
|
||||
g += shadowVal * weight
|
||||
b += shadowVal * weight
|
||||
}
|
||||
|
||||
val finalR = (r.coerceIn(0.0f, 1.0f) * 255f).toInt()
|
||||
val finalG = (g.coerceIn(0.0f, 1.0f) * 255f).toInt()
|
||||
val finalB = (b.coerceIn(0.0f, 1.0f) * 255f).toInt()
|
||||
|
||||
pixels[i] = (0xFF shl 24) or (finalR shl 16) or (finalG shl 8) or finalB
|
||||
}
|
||||
filteredBitmap.setPixels(pixels, 0, width, 0, 0, width, height)
|
||||
}
|
||||
|
||||
// 4. Film Grain effect
|
||||
if (preset.grain.grainAmount > 0f) {
|
||||
val grainAmount = preset.grain.grainAmount
|
||||
@@ -2261,6 +2212,85 @@ class MainActivity : AppCompatActivity() {
|
||||
return upscaled
|
||||
}
|
||||
|
||||
private fun applyHighImpactPreset(inputBitmap: android.graphics.Bitmap, preset: ColorPreset): android.graphics.Bitmap {
|
||||
val w = inputBitmap.width
|
||||
val h = inputBitmap.height
|
||||
val outputBitmap = android.graphics.Bitmap.createBitmap(w, h, android.graphics.Bitmap.Config.ARGB_8888)
|
||||
|
||||
// KHUẾCH ĐẠI BIÊN ĐỘ: Nhân hệ số cường độ tác động để thông số thay đổi rõ rệt
|
||||
val enhancedBrightness = preset.basic.brightness * 1.5f // Tăng lực cho Brightness
|
||||
val enhancedContrast = preset.basic.contrast + 1f // Giữ nguyên dải Contrast [0.0 - 2.0]
|
||||
val saturationVal = (preset.basic.saturation + preset.basic.vibrance * 0.5f) + 1f
|
||||
val temp = preset.basic.temperature
|
||||
val tint = preset.basic.tint
|
||||
|
||||
// Temperature scales
|
||||
val rScaleTemp = 1f + temp * 0.12f
|
||||
val gScaleTemp = 1f + temp * 0.04f
|
||||
val bScaleTemp = 1f - temp * 0.12f
|
||||
|
||||
// Tint scales
|
||||
val rScaleTint = 1f + tint * 0.06f
|
||||
val gScaleTint = 1f - tint * 0.12f
|
||||
val bScaleTint = 1f + tint * 0.06f
|
||||
|
||||
val pixels = IntArray(w * h)
|
||||
inputBitmap.getPixels(pixels, 0, w, 0, 0, w, h)
|
||||
|
||||
for (i in 0 until (w * h)) {
|
||||
val pixel = pixels[i]
|
||||
|
||||
var r = ((pixel shr 16) and 0xFF) / 255.0f
|
||||
var g = ((pixel shr 8) and 0xFF) / 255.0f
|
||||
var b = (pixel and 0xFF) / 255.0f
|
||||
|
||||
// 1. CẢI TIẾN BRIGHTNESS & CONTRAST (Áp dụng công thức dốc phi tuyến tính)
|
||||
r = (r - 0.5f) * enhancedContrast + 0.5f + enhancedBrightness
|
||||
g = (g - 0.5f) * enhancedContrast + 0.5f + enhancedBrightness
|
||||
b = (b - 0.5f) * enhancedContrast + 0.5f + enhancedBrightness
|
||||
|
||||
// Tính toán độ sáng thực tế (Luminance) của pixel hiện tại sau khi chỉnh Brightness/Contrast
|
||||
val luminance = (0.2126f * r + 0.7152f * g + 0.0722f * b).coerceIn(0.0f, 1.0f)
|
||||
|
||||
// 2. SỬA LỖI HIGHLIGHT: Dùng hàm S-Curve phi tuyến tính thay vì cộng trừ thông thường
|
||||
if (luminance > 0.5f) {
|
||||
val highlightFactor = Math.pow(((luminance - 0.5f) / 0.5f).toDouble(), 1.5).toFloat()
|
||||
r += preset.basic.highlight * highlightFactor * 0.4f
|
||||
g += preset.basic.highlight * highlightFactor * 0.4f
|
||||
b += preset.basic.highlight * highlightFactor * 0.4f
|
||||
}
|
||||
|
||||
// 3. SỬA LỖI SHADOW: Tương tự như Highlight, dùng hàm lũy thừa ngược cho vùng tối
|
||||
if (luminance < 0.6f) {
|
||||
val shadowFactor = Math.pow(((0.6f - luminance) / 0.6f).toDouble(), 1.5).toFloat()
|
||||
r += preset.basic.shadow * shadowFactor * 0.5f
|
||||
g += preset.basic.shadow * shadowFactor * 0.5f
|
||||
b += preset.basic.shadow * shadowFactor * 0.5f
|
||||
}
|
||||
|
||||
// 4. XỬ LÝ SẮC ĐỘ (Saturation / Vibrance)
|
||||
val finalLuminance = (0.2126f * r + 0.7152f * g + 0.0722f * b).coerceIn(0.0f, 1.0f)
|
||||
r = finalLuminance + (r - finalLuminance) * saturationVal
|
||||
g = finalLuminance + (g - finalLuminance) * saturationVal
|
||||
b = finalLuminance + (b - finalLuminance) * saturationVal
|
||||
|
||||
// 5. TEMPERATURE & TINT
|
||||
r *= rScaleTemp * rScaleTint
|
||||
g *= gScaleTemp * gScaleTint
|
||||
b *= bScaleTemp * bScaleTint
|
||||
|
||||
// Kiểm soát biên độ bảo vệ hạt màu không vượt quá giới hạn [0, 255]
|
||||
val finalR = (r.coerceIn(0.0f, 1.0f) * 255).toInt()
|
||||
val finalG = (g.coerceIn(0.0f, 1.0f) * 255).toInt()
|
||||
val finalB = (b.coerceIn(0.0f, 1.0f) * 255).toInt()
|
||||
|
||||
pixels[i] = (0xFF shl 24) or (finalR shl 16) or (finalG shl 8) or finalB
|
||||
}
|
||||
|
||||
outputBitmap.setPixels(pixels, 0, w, 0, 0, w, h)
|
||||
return outputBitmap
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor.shutdown()
|
||||
|
||||
Reference in New Issue
Block a user