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
|
||||
echo "GD: " . (extension_loaded('gd') ? 'KYLLÄ' : 'EI') . "\n";
|
||||
echo "Imagick: " . (extension_loaded('imagick') ? 'KYLLÄ' : 'EI') . "\n";
|
||||
if (extension_loaded('gd')) {
|
||||
echo "GD info: " . json_encode(gd_info()) . "\n";
|
||||
echo "PHP " . PHP_VERSION . " (" . php_sapi_name() . ")\n";
|
||||
echo "php.ini: " . php_ini_loaded_file() . "\n\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() {
|
||||
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();
|
||||
formData.append('logo', this.files[0]);
|
||||
formData.append('logo', file);
|
||||
formData.append('company_id', currentCompanyDetail);
|
||||
try {
|
||||
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
|
||||
const comp = companiesTabData.find(c => c.id === currentCompanyDetail);
|
||||
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); }
|
||||
this.value = ''; // Reset file input
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user