🚧 wip: chekkupointo
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Color Arg Test</title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.left-panel {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
#image-preview {
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
.control-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
#color-box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid #000;
|
||||
margin-top: 20px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="left-panel">
|
||||
<input type="file" id="image-upload" accept="image/*" />
|
||||
<br />
|
||||
<img id="image-preview" alt="Image Preview" />
|
||||
</div>
|
||||
|
||||
<div class="right-panel">
|
||||
<div class="control-group">
|
||||
<label for="saturation-power">Saturation Power: <span id="sat-val">1.0</span></label>
|
||||
<input type="range" id="saturation-power" min="1" max="5" step="0.1" value="1" />
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label for="lightness-power">Lightness Power: <span id="light-val">1.0</span></label>
|
||||
<input type="range" id="lightness-power" min="1" max="5" step="0.1" value="1" />
|
||||
</div>
|
||||
|
||||
<div id="color-box"></div>
|
||||
</div>
|
||||
|
||||
<canvas id="hidden-canvas" style="display: none"></canvas>
|
||||
|
||||
<script>
|
||||
const imageUpload = document.getElementById('image-upload');
|
||||
const imagePreview = document.getElementById('image-preview');
|
||||
const hiddenCanvas = document.getElementById('hidden-canvas');
|
||||
const ctx = hiddenCanvas.getContext('2d');
|
||||
|
||||
const satSlider = document.getElementById('saturation-power');
|
||||
const lightSlider = document.getElementById('lightness-power');
|
||||
const satValDisplay = document.getElementById('sat-val');
|
||||
const lightValDisplay = document.getElementById('light-val');
|
||||
const colorBox = document.getElementById('color-box');
|
||||
|
||||
let currentPixelBuffer = null;
|
||||
|
||||
function rgbToHsl(r, g, b) {
|
||||
r /= 255;
|
||||
g /= 255;
|
||||
b /= 255;
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
let h,
|
||||
s,
|
||||
l = (max + min) / 2;
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0;
|
||||
} else {
|
||||
const d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h * 360, s * 255, l * 255];
|
||||
}
|
||||
|
||||
function foobar(rgbaBuffer, satPower, lightPower) {
|
||||
const numBins = 36;
|
||||
const bins = Array.from({ length: numBins }, () => ({
|
||||
totalWeight: 0,
|
||||
sumR: 0,
|
||||
sumG: 0,
|
||||
sumB: 0,
|
||||
}));
|
||||
|
||||
for (let i = 0; i < rgbaBuffer.length; i += 4) {
|
||||
const r = rgbaBuffer[i];
|
||||
const g = rgbaBuffer[i + 1];
|
||||
const b = rgbaBuffer[i + 2];
|
||||
const a = rgbaBuffer[i + 3];
|
||||
|
||||
if (a < 5) continue;
|
||||
|
||||
const [h, s, l] = rgbToHsl(r, g, b);
|
||||
|
||||
if (s === 0) continue;
|
||||
|
||||
const sNorm = s / 255.0;
|
||||
const wS = Math.pow(sNorm, satPower);
|
||||
|
||||
const dist = Math.abs(l - 128.0) / 128.0;
|
||||
const lNorm = 1.0 - dist;
|
||||
const wL = Math.pow(lNorm, lightPower);
|
||||
|
||||
const weight = wS * wL;
|
||||
|
||||
if (weight < 0.05) continue;
|
||||
|
||||
const binIndex = Math.floor(h / 10) % numBins;
|
||||
|
||||
bins[binIndex].totalWeight += weight;
|
||||
bins[binIndex].sumR += r * weight;
|
||||
bins[binIndex].sumG += g * weight;
|
||||
bins[binIndex].sumB += b * weight;
|
||||
}
|
||||
|
||||
let maxBinIndex = -1;
|
||||
let maxWeight = 0;
|
||||
|
||||
for (let i = 0; i < numBins; i++) {
|
||||
if (bins[i].totalWeight > maxWeight) {
|
||||
maxWeight = bins[i].totalWeight;
|
||||
maxBinIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxBinIndex === -1 || maxWeight <= 0) {
|
||||
return `rgb(128, 128, 128)`;
|
||||
}
|
||||
|
||||
const winningBin = bins[maxBinIndex];
|
||||
const finalR = Math.round(winningBin.sumR / winningBin.totalWeight);
|
||||
const finalG = Math.round(winningBin.sumG / winningBin.totalWeight);
|
||||
const finalB = Math.round(winningBin.sumB / winningBin.totalWeight);
|
||||
|
||||
return `rgb(${finalR}, ${finalG}, ${finalB})`;
|
||||
}
|
||||
|
||||
function updateColor() {
|
||||
if (!currentPixelBuffer) return;
|
||||
|
||||
const satPower = parseFloat(satSlider.value);
|
||||
const lightPower = parseFloat(lightSlider.value);
|
||||
|
||||
satValDisplay.textContent = satPower.toFixed(1);
|
||||
lightValDisplay.textContent = lightPower.toFixed(1);
|
||||
|
||||
const color = foobar(currentPixelBuffer, satPower, lightPower);
|
||||
colorBox.style.backgroundColor = color;
|
||||
}
|
||||
|
||||
imageUpload.addEventListener('change', function (e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
const img = new Image();
|
||||
img.onload = function () {
|
||||
imagePreview.src = event.target.result;
|
||||
imagePreview.style.display = 'block';
|
||||
|
||||
hiddenCanvas.width = img.width;
|
||||
hiddenCanvas.height = img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
currentPixelBuffer = imageData.data;
|
||||
|
||||
updateColor();
|
||||
};
|
||||
img.src = event.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
satSlider.addEventListener('input', updateColor);
|
||||
lightSlider.addEventListener('input', updateColor);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user