feat: auto-extract color from logo + PHP extension check
Added extractDominantColor() JS function that picks the dominant color from uploaded logo and suggests it as theme color. Updated gdcheck.php to show all needed extensions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
17
gdcheck.php
17
gdcheck.php
@@ -1,6 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
echo "GD: " . (extension_loaded('gd') ? 'KYLLÄ' : 'EI') . "\n";
|
echo "PHP " . PHP_VERSION . " (" . php_sapi_name() . ")\n";
|
||||||
echo "Imagick: " . (extension_loaded('imagick') ? 'KYLLÄ' : 'EI') . "\n";
|
echo "php.ini: " . php_ini_loaded_file() . "\n\n";
|
||||||
if (extension_loaded('gd')) {
|
|
||||||
echo "GD info: " . json_encode(gd_info()) . "\n";
|
$check = ['pdo', 'pdo_mysql', 'gd', 'imagick', 'fileinfo', 'mbstring', 'curl', 'openssl', 'json', 'session', 'mysqli', 'imap', 'zip', 'xml', 'dom', 'simplexml'];
|
||||||
|
echo "=== Tarvittavat laajennukset ===\n";
|
||||||
|
foreach ($check as $ext) {
|
||||||
|
echo ($ext . ': ' . str_pad('', 15 - strlen($ext)) . (extension_loaded($ext) ? '✅ KYLLÄ' : '❌ EI')) . "\n";
|
||||||
}
|
}
|
||||||
|
echo "\n=== Kaikki ladatut ===\n";
|
||||||
|
echo implode(', ', get_loaded_extensions()) . "\n";
|
||||||
|
|
||||||
|
echo "\n=== Lisätietojen ini-polut ===\n";
|
||||||
|
$scanDir = php_ini_scanned_files();
|
||||||
|
echo $scanDir ?: "(ei skannattu lisä-ini-tiedostoja)\n";
|
||||||
|
|||||||
76
script.js
76
script.js
@@ -1884,11 +1884,69 @@ document.getElementById('company-edit-color-text').addEventListener('input', fun
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logo-upload
|
// Poimi hallitseva väri kuvasta (canvas)
|
||||||
|
function extractDominantColor(file) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const img = new Image();
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const size = 50; // Pieni koko nopeuttaa
|
||||||
|
canvas.width = size;
|
||||||
|
canvas.height = size;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0, size, size);
|
||||||
|
const pixels = ctx.getImageData(0, 0, size, size).data;
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
// Laske värien esiintymät (ryhmiteltynä 32-askeleen tarkkuudella)
|
||||||
|
const colorCounts = {};
|
||||||
|
for (let i = 0; i < pixels.length; i += 4) {
|
||||||
|
const r = pixels[i], g = pixels[i+1], b = pixels[i+2], a = pixels[i+3];
|
||||||
|
if (a < 128) continue; // Ohita läpinäkyvät
|
||||||
|
// Ohita lähes valkoiset, mustat ja harmaat
|
||||||
|
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||||
|
const saturation = max === 0 ? 0 : (max - min) / max;
|
||||||
|
if (max > 230 && min > 200) continue; // Valkoinen
|
||||||
|
if (max < 30) continue; // Musta
|
||||||
|
if (saturation < 0.15 && max > 60) continue; // Harmaa
|
||||||
|
// Ryhmittele
|
||||||
|
const qr = Math.round(r / 32) * 32;
|
||||||
|
const qg = Math.round(g / 32) * 32;
|
||||||
|
const qb = Math.round(b / 32) * 32;
|
||||||
|
const key = `${qr},${qg},${qb}`;
|
||||||
|
colorCounts[key] = (colorCounts[key] || 0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Etsi yleisin
|
||||||
|
let bestKey = null, bestCount = 0;
|
||||||
|
for (const [key, count] of Object.entries(colorCounts)) {
|
||||||
|
if (count > bestCount) { bestCount = count; bestKey = key; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestKey) {
|
||||||
|
const [r, g, b] = bestKey.split(',').map(Number);
|
||||||
|
const hex = '#' + [r, g, b].map(v => Math.min(255, v).toString(16).padStart(2, '0')).join('');
|
||||||
|
resolve(hex);
|
||||||
|
} else {
|
||||||
|
resolve(null); // Ei löytynyt selkeää väriä
|
||||||
|
}
|
||||||
|
};
|
||||||
|
img.onerror = () => { URL.revokeObjectURL(url); resolve(null); };
|
||||||
|
img.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logo-upload — poimi väri automaattisesti
|
||||||
document.getElementById('company-logo-upload').addEventListener('change', async function() {
|
document.getElementById('company-logo-upload').addEventListener('change', async function() {
|
||||||
if (!this.files[0] || !currentCompanyDetail) return;
|
if (!this.files[0] || !currentCompanyDetail) return;
|
||||||
|
const file = this.files[0];
|
||||||
|
|
||||||
|
// Poimi väri logosta ennen uploadia
|
||||||
|
const dominantColor = await extractDominantColor(file);
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('logo', this.files[0]);
|
formData.append('logo', file);
|
||||||
formData.append('company_id', currentCompanyDetail);
|
formData.append('company_id', currentCompanyDetail);
|
||||||
try {
|
try {
|
||||||
const res = await fetch('api.php?action=company_logo_upload', { method: 'POST', body: formData, credentials: 'include' });
|
const res = await fetch('api.php?action=company_logo_upload', { method: 'POST', body: formData, credentials: 'include' });
|
||||||
@@ -1901,6 +1959,20 @@ document.getElementById('company-logo-upload').addEventListener('change', async
|
|||||||
// Päivitä paikallinen data
|
// Päivitä paikallinen data
|
||||||
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
||||||
if (comp) comp.logo_file = data.logo_file;
|
if (comp) comp.logo_file = data.logo_file;
|
||||||
|
|
||||||
|
// Aseta logosta poimittu väri teemaväriksi
|
||||||
|
if (dominantColor) {
|
||||||
|
const colorInput = document.getElementById('company-edit-color');
|
||||||
|
if (colorInput) {
|
||||||
|
colorInput.value = dominantColor;
|
||||||
|
// Näytä ilmoitus
|
||||||
|
const msg = document.createElement('span');
|
||||||
|
msg.textContent = ` Väri ${dominantColor} poimittu logosta`;
|
||||||
|
msg.style.cssText = 'color:#27ae60;font-size:0.85rem;margin-left:8px;';
|
||||||
|
colorInput.parentElement.appendChild(msg);
|
||||||
|
setTimeout(() => msg.remove(), 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
this.value = ''; // Reset file input
|
this.value = ''; // Reset file input
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user