MediaWiki:Gadget-LabelScan.js: Unterschied zwischen den Versionen
Erscheinungsbild
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Admin (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| Zeile 152: | Zeile 152: | ||
} else { | } else { | ||
bind(); | bind(); | ||
// ----- Helpers: Status/Preview/Datei ----- | |||
let _pickedFile = null; | |||
function setStatus(t){ const el=document.getElementById('ados-scan-status'); if(el) el.textContent=t||''; } | |||
function showPreview(file){ | |||
const prev=document.getElementById('ados-scan-preview'); | |||
if(!prev) return; | |||
const url=URL.createObjectURL(file); | |||
prev.innerHTML = `<img src="${url}" alt="Vorschau" style="max-width:100%; border-radius:6px;">`; | |||
setStatus('Bild bereit.'); | |||
} | |||
function getSelectedFile(){ | |||
const c=document.getElementById('ados-scan-file-camera'); | |||
const g=document.getElementById('ados-scan-file-gallery'); | |||
return _pickedFile || (c && c.files && c.files[0]) || (g && g.files && g.files[0]) || null; | |||
} | |||
// ----- Buttons sauber binden ----- | |||
(function wirePickers(){ | |||
const btnCam = document.getElementById('ados-scan-btn-camera'); | |||
const btnGal = document.getElementById('ados-scan-btn-gallery'); | |||
const inCam = document.getElementById('ados-scan-file-camera'); | |||
const inGal = document.getElementById('ados-scan-file-gallery'); | |||
if (btnCam && inCam) { | |||
btnCam.addEventListener('click', function(ev){ | |||
ev.preventDefault(); ev.stopPropagation(); | |||
inCam.click(); | |||
}); | |||
inCam.addEventListener('change', function(){ | |||
if (inCam.files && inCam.files[0]) { | |||
_pickedFile = inCam.files[0]; | |||
showPreview(_pickedFile); | |||
} | |||
}); | |||
} | |||
if (btnGal && inGal) { | |||
btnGal.addEventListener('click', function(ev){ | |||
ev.preventDefault(); ev.stopPropagation(); | |||
inGal.click(); | |||
}); | |||
inGal.addEventListener('change', function(){ | |||
if (inGal.files && inGal.files[0]) { | |||
_pickedFile = inGal.files[0]; | |||
showPreview(_pickedFile); | |||
} | |||
}); | |||
} | |||
})(); | |||
// ----- Drag&Drop auf der Dropzone ----- | |||
(function wireDropzone(){ | |||
const drop = document.getElementById('ados-scan-drop'); | |||
if (!drop) return; | |||
const stop = e => { e.preventDefault(); e.stopPropagation(); }; | |||
['dragenter','dragover','dragleave','drop'].forEach(evt => drop.addEventListener(evt, stop)); | |||
drop.addEventListener('drop', e => { | |||
const f = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0]; | |||
if (f) { _pickedFile = f; showPreview(f); } | |||
}); | |||
})(); | |||
// ----- „Erkennen & suchen“ nutzt immer die aktuell gewählte Datei ----- | |||
(function wireRun(){ | |||
const runBtn = document.getElementById('ados-scan-run'); | |||
if (!runBtn) return; | |||
runBtn.addEventListener('click', async function(ev){ | |||
ev.preventDefault(); | |||
const file = getSelectedFile(); | |||
if (!file) { alert('Bitte Foto aufnehmen oder Datei wählen.'); return; } | |||
// HIER: dein bestehender Erkennungs-Workflow (phash / Vergleich) | |||
// Beispiel: | |||
// setStatus('Berechne Fingerabdruck …'); const img = await fileToImage(file); | |||
// const hash = computePhash(img); … vergleichen … renderResults(…) | |||
}); | |||
})(); | |||
} | } | ||
})(); | })(); | ||
Version vom 7. November 2025, 22:39 Uhr
// Kamera öffnen
document.getElementById('ados-scan-btn-camera')?.addEventListener('click', () => {
document.getElementById('ados-scan-file-camera').click();
});
// Galerie öffnen
document.getElementById('ados-scan-btn-gallery')?.addEventListener('click', () => {
document.getElementById('ados-scan-file-gallery').click();
});
// Vorschau für beide Inputs
['ados-scan-file-camera','ados-scan-file-gallery'].forEach(id => {
const el = document.getElementById(id);
if (!el) return;
el.addEventListener('change', () => {
if (el.files && el.files[0]) {
const url = URL.createObjectURL(el.files[0]);
document.getElementById('ados-scan-preview').innerHTML = `<img src="${url}" style="max-width:100%; border-radius:6px;">`;
document.getElementById('ados-scan-status').textContent = 'Bild bereit.';
}
});
});
/* global mw */
(function () {
'use strict';
// === Hilfsfunktionen =====================================================
async function fileToImage (file) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = URL.createObjectURL(file);
});
}
function getCanvas (img, size = 32) {
const c = document.createElement('canvas');
c.width = c.height = size;
const ctx = c.getContext('2d');
ctx.drawImage(img, 0, 0, size, size);
return ctx.getImageData(0, 0, size, size).data;
}
function computePhash (img) {
const size = 32;
const pixels = getCanvas(img, size);
const gray = [];
for (let i = 0; i < pixels.length; i += 4) {
gray.push(0.299 * pixels[i] + 0.587 * pixels[i + 1] + 0.114 * pixels[i + 2]);
}
const avg = gray.reduce((a, b) => a + b, 0) / gray.length;
const bits = gray.map(v => (v > avg ? 1 : 0));
let hash = '';
for (let i = 0; i < bits.length; i += 4) {
const nibble = bits.slice(i, i + 4).reduce((a, b, j) => a | (b << (3 - j)), 0);
hash += nibble.toString(16);
}
return hash;
}
function hamming (h1, h2) {
let d = 0;
const len = Math.min(h1.length, h2.length);
for (let i = 0; i < len; i++) {
const x = parseInt(h1[i], 16) ^ parseInt(h2[i], 16);
d += x.toString(2).replace(/0/g, '').length;
}
return d;
}
async function loadIndex () {
const url = mw.util.getUrl('MediaWiki:Gadget-LabelScan-index.json', { action: 'raw', ctype: 'application/json' });
const res = await fetch(url);
return res.json();
}
// === UI-Helfer ===========================================================
function showPreview (file) {
const prev = document.getElementById('ados-scan-preview');
if (prev) prev.innerHTML = `<img alt="Vorschau" src="${URL.createObjectURL(file)}">`;
}
function setStatus (t) {
const el = document.getElementById('ados-scan-status');
if (el) el.textContent = t;
}
function renderResults (hits) {
const box = document.getElementById('ados-scan-results');
box.innerHTML = '';
if (!hits.length) {
box.innerHTML = '<div>Keine klaren Treffer gefunden.</div>';
return;
}
hits.forEach(h => {
box.innerHTML += `
<div class="ados-hit">
<a href="${mw.util.getUrl(h.title)}">
<img src="${h.thumb}" alt="${h.title}">
<br><b>${mw.html.escape(h.title)}</b>
</a>
<small>Distanz: ${h.dist}</small>
</div>`;
});
}
// === Haupt-Bindung =======================================================
async function bind () {
const runBtn = document.getElementById('ados-scan-run');
const fileIn = document.getElementById('ados-scan-file');
const bigBtn = document.getElementById('ados-scan-bigbtn');
if (!runBtn || !fileIn) return;
bigBtn?.addEventListener('click', () => fileIn.click());
fileIn.addEventListener('change', e => { if (e.target.files[0]) showPreview(e.target.files[0]); });
runBtn.addEventListener('click', async ev => {
ev.preventDefault();
const file = fileIn.files[0];
if (!file) return alert('Bitte ein Bild wählen.');
try {
setStatus('Berechne Hash …');
const img = await fileToImage(file);
const ph = computePhash(img);
setStatus('Lade Index …');
const idx = await loadIndex();
setStatus('Vergleiche …');
const scored = idx.map(it => ({ ...it, dist: hamming(ph, it.phash) }));
scored.sort((a, b) => a.dist - b.dist);
const top = scored.slice(0, 5);
renderResults(top);
setStatus('Fertig.');
} catch (e) {
console.error('[LabelScan]', e);
setStatus('Fehler bei Erkennung.');
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', bind);
} else {
bind();
// ----- Helpers: Status/Preview/Datei -----
let _pickedFile = null;
function setStatus(t){ const el=document.getElementById('ados-scan-status'); if(el) el.textContent=t||''; }
function showPreview(file){
const prev=document.getElementById('ados-scan-preview');
if(!prev) return;
const url=URL.createObjectURL(file);
prev.innerHTML = `<img src="${url}" alt="Vorschau" style="max-width:100%; border-radius:6px;">`;
setStatus('Bild bereit.');
}
function getSelectedFile(){
const c=document.getElementById('ados-scan-file-camera');
const g=document.getElementById('ados-scan-file-gallery');
return _pickedFile || (c && c.files && c.files[0]) || (g && g.files && g.files[0]) || null;
}
// ----- Buttons sauber binden -----
(function wirePickers(){
const btnCam = document.getElementById('ados-scan-btn-camera');
const btnGal = document.getElementById('ados-scan-btn-gallery');
const inCam = document.getElementById('ados-scan-file-camera');
const inGal = document.getElementById('ados-scan-file-gallery');
if (btnCam && inCam) {
btnCam.addEventListener('click', function(ev){
ev.preventDefault(); ev.stopPropagation();
inCam.click();
});
inCam.addEventListener('change', function(){
if (inCam.files && inCam.files[0]) {
_pickedFile = inCam.files[0];
showPreview(_pickedFile);
}
});
}
if (btnGal && inGal) {
btnGal.addEventListener('click', function(ev){
ev.preventDefault(); ev.stopPropagation();
inGal.click();
});
inGal.addEventListener('change', function(){
if (inGal.files && inGal.files[0]) {
_pickedFile = inGal.files[0];
showPreview(_pickedFile);
}
});
}
})();
// ----- Drag&Drop auf der Dropzone -----
(function wireDropzone(){
const drop = document.getElementById('ados-scan-drop');
if (!drop) return;
const stop = e => { e.preventDefault(); e.stopPropagation(); };
['dragenter','dragover','dragleave','drop'].forEach(evt => drop.addEventListener(evt, stop));
drop.addEventListener('drop', e => {
const f = e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0];
if (f) { _pickedFile = f; showPreview(f); }
});
})();
// ----- „Erkennen & suchen“ nutzt immer die aktuell gewählte Datei -----
(function wireRun(){
const runBtn = document.getElementById('ados-scan-run');
if (!runBtn) return;
runBtn.addEventListener('click', async function(ev){
ev.preventDefault();
const file = getSelectedFile();
if (!file) { alert('Bitte Foto aufnehmen oder Datei wählen.'); return; }
// HIER: dein bestehender Erkennungs-Workflow (phash / Vergleich)
// Beispiel:
// setStatus('Berechne Fingerabdruck …'); const img = await fileToImage(file);
// const hash = computePhash(img); … vergleichen … renderResults(…)
});
})();
}
})();