Bắt đầu sửa lỗi

This commit is contained in:
2026-07-17 09:33:24 +07:00
commit 2775662b62
134 changed files with 28571 additions and 0 deletions
+182
View File
@@ -0,0 +1,182 @@
// Tanner Helland's Kelvin to RGB approximation
// Kelvin range: 1000K to 40000K (we use 2500K to 10000K)
export function kelvinToRGB(kelvin: number): { r: number; g: number; b: number } {
const temp = Math.max(1000, Math.min(40000, kelvin)) / 100;
let r = 0;
let g = 0;
let b = 0;
// Red
if (temp <= 66) {
r = 255;
} else {
r = temp - 60;
r = 329.698727446 * Math.pow(r, -0.1332047592);
r = Math.max(0, Math.min(255, r));
}
// Green
if (temp <= 66) {
g = temp;
g = 99.4708025861 * Math.log(g) - 161.1195681661;
g = Math.max(0, Math.min(255, g));
} else {
g = temp - 60;
g = 288.1221695283 * Math.pow(g, -0.0755148492);
g = Math.max(0, Math.min(255, g));
}
// Blue
if (temp >= 66) {
b = 255;
} else {
if (temp <= 19) {
b = 0;
} else {
b = temp - 10;
b = 138.5177312231 * Math.log(b) - 305.0447927307;
b = Math.max(0, Math.min(255, b));
}
}
return { r: r / 255, g: g / 255, b: b / 255 };
}
// Generate a 4x5 ColorMatrix (array of 20 floats) based on base style and adjustments
export function getSkiaColorMatrix(
baseFilter: 'classic-neg' | 'provia' | 'velvia' | 'monochrome' | 'none',
exposure: number, // -10 to +10
saturation: number, // -10 to +10
temperature: number, // 2500 to 10000
tint: number, // -10 to +10
colorChrome: 'none' | 'weak' | 'strong'
): number[] {
// 1. Start with Identity Matrix
let matrix = [
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
];
// 2. Base Filters
if (baseFilter === 'classic-neg') {
// Classic Neg: high contrast, desaturated reds/greens, warm/amber cast
matrix = [
1.15, -0.05, -0.05, 0, 0.05,
-0.05, 1.05, -0.05, 0, 0.02,
-0.08, -0.08, 0.95, 0, -0.02,
0, 0, 0, 1, 0,
];
} else if (baseFilter === 'provia') {
// Provia: standard natural colors, balanced tones
matrix = [
1.02, 0, 0, 0, 0,
0, 1.02, 0, 0, 0,
0, 0, 1.02, 0, 0,
0, 0, 0, 1, 0,
];
} else if (baseFilter === 'velvia') {
// Velvia: vivid colors, high saturation, deep blacks
matrix = [
1.25, -0.05, -0.05, 0, -0.02,
-0.05, 1.25, -0.05, 0, -0.02,
-0.05, -0.05, 1.25, 0, -0.02,
0, 0, 0, 1, 0,
];
} else if (baseFilter === 'monochrome') {
// Classic black and white filter (luminance weights)
const r = 0.2126;
const g = 0.7152;
const b = 0.0722;
matrix = [
r, g, b, 0, 0,
r, g, b, 0, 0,
r, g, b, 0, 0,
0, 0, 0, 1, 0,
];
}
// 3. Apply Saturation adjustment (standard color matrix transformation)
if (baseFilter !== 'monochrome' && saturation !== 0) {
const s = 1 + (saturation / 10) * 0.5; // -10 maps to 0.5x, +10 maps to 1.5x saturation
const invS = 1 - s;
const r = 0.213 * invS;
const g = 0.715 * invS;
const b = 0.072 * invS;
const satMat = [
r + s, g, b, 0, 0,
r, g + s, b, 0, 0,
r, g, b + s, 0, 0,
0, 0, 0, 1, 0,
];
matrix = multiplyMatrices(satMat, matrix);
}
// 4. Color Chrome effect (enhances deep colors without shifting white point)
if (baseFilter !== 'monochrome' && colorChrome !== 'none') {
const factor = colorChrome === 'strong' ? 0.25 : 0.12;
// Boost reds and blues slightly, deep shadows get more saturated
const chromeMat = [
1 + factor, -factor/2, -factor/2, 0, 0,
-factor/2, 1, -factor/2, 0, 0,
-factor/2, -factor/2, 1 + factor, 0, 0,
0, 0, 0, 1, 0,
];
matrix = multiplyMatrices(chromeMat, matrix);
}
// 5. White Balance (Kelvin Temperature and Tint)
const rgbTemp = kelvinToRGB(temperature);
// Tint adjustment: -10 is Green (+G), +10 is Magenta (+R, +B)
const tintR = tint > 0 ? (tint / 10) * 0.08 : 0;
const tintG = tint < 0 ? (-tint / 10) * 0.08 : 0;
const tintB = tint > 0 ? (tint / 10) * 0.08 : 0;
const wbMat = [
rgbTemp.r + tintR, 0, 0, 0, 0,
0, rgbTemp.g + tintG, 0, 0, 0,
0, 0, rgbTemp.b + tintB, 0, 0,
0, 0, 0, 1, 0,
];
matrix = multiplyMatrices(wbMat, matrix);
// 6. Exposure adjustment (Simple offset in fifth column and slight scaling)
if (exposure !== 0) {
const scale = 1 + (exposure / 10) * 0.2; // scaling multiplier
const offset = (exposure / 10) * 0.15; // translation offset
const expMat = [
scale, 0, 0, 0, offset,
0, scale, 0, 0, offset,
0, 0, scale, 0, offset,
0, 0, 0, 1, 0,
];
matrix = multiplyMatrices(expMat, matrix);
}
return matrix;
}
// 4x5 Matrix multiplication utility: A * B
function multiplyMatrices(a: number[], b: number[]): number[] {
const result = new Array(20).fill(0);
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
result[r * 5 + c] =
a[r * 5 + 0] * b[0 * 5 + c] +
a[r * 5 + 1] * b[1 * 5 + c] +
a[r * 5 + 2] * b[2 * 5 + c] +
a[r * 5 + 3] * b[3 * 5 + c];
}
// Handle the 5th column translation translation
result[r * 5 + 4] =
a[r * 5 + 0] * b[0 * 5 + 4] +
a[r * 5 + 1] * b[1 * 5 + 4] +
a[r * 5 + 2] * b[2 * 5 + 4] +
a[r * 5 + 3] * b[3 * 5 + 4] +
a[r * 5 + 4];
}
return result;
}