2021-04-28 20:47:11 +02:00
<!DOCTYPE HTML>
2021-06-12 19:57:59 +02:00
<!-- Photo_mem Version 2.1
Copyright © 2017-2021 J. PLISSON
Licence AGPL v3.0+
2.0 mai 2021 ajout détection de visages
2.1 juin 2021 refonte en une seule application
amélioration saisie des fichiers
ajout fonction modification des personnes
-->
2021-04-28 20:47:11 +02:00
< html >
< head >
< meta charset = "utf-8" / >
< style >
circle {
fill: transparent;
stroke: black;
stroke-width: 2;
}
2021-06-12 19:57:59 +02:00
#bouton_image {background-color:blue;color:white;height: 30px;}
#menu_modif {
display: block;
color: black;
background-color: gainsboro;
cursor: pointer;
border: 2px solid;
border-radius: 6px;
text-align: center;
position: absolute;
width: 80px;
z-index: 10;
}
2021-04-28 20:47:11 +02:00
#ajout {
border:2px solid red;
border-radius: 10px;
top: 100px;
left: 200px;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 1em;
background-color: Azure;
width: 230px;
}
#ajout input:focus {border: solid 2px green;}
.cotecote {display: inline;}
.visible { visibility:visible; }
.invisible { visibility:hidden; }
.etiq {
background-color:oldlace;
border:1px solid blue;
border-radius: 10px;
position:absolute;
font-family: Arial;
font-size: 13px;
left:-200px;
top: 100px;
}
.tit {
background-color:LightYellow;
border: 2px solid Yellow;
border-radius: 5px;
position:absolute;
left:-200px;
top: 100px;
}
< / style >
< / head >
< body >
2021-06-12 19:57:59 +02:00
< input id = "fichiers" multiple type = "file" class = cotecote style = "display:none" / >
< button id = "bouton_image" onclick = "fichiers.click()" title = "Charger une image et le XML associé" > Choix de la photo< / button >
2021-04-28 20:47:11 +02:00
< input id = "file" type = "button" class = cotecote value = "Enregistrer xml" onclick = "enregistrer_fichier(enreg_xml)" / >
< input id = "file" type = "button" class = cotecote value = "Enregistrer image " onclick = "image_finale()" / >
2021-06-12 19:57:59 +02:00
< p id = "status" class = cotecote > OpenCV.js chargement en cours...< / p >
2021-04-28 20:47:11 +02:00
< div style = "position: relative; " >
< img src = "" id = "ima_fond" style = "position: absolute; left: 0; top: 0; z-index: 0;" >
< / div >
< svg class = "invisible" style = "position: absolute" ; >
< circle id = "cirsvg" cx = "30" cy = "30" r = "28" / >
< / svg >
< div id = "ajout" class = "invisible" style = "position: relative; z-index: 1;" >
2021-06-12 19:57:59 +02:00
< form name = "ajout_personne" id = "ajout_personne" >
2021-04-28 20:47:11 +02:00
< center > < font color = "green" > NOUVELLE PERSONNE< / font > < / center >
Nom : < INPUT type = "text" name = "nom" id = "nom" autofocus > < BR >
Née : < INPUT type = "text" name = "nom_jf" id = "nom_jeune_fille" > < BR >
Prénom : < INPUT type = "text" name = "prénom" id = "prenom" > < BR >
Année : < INPUT type = "text" name = "année" id = "annee" > < BR >
Note : < INPUT type = "text" name = "note" id = "note" > < BR >
2021-06-12 19:57:59 +02:00
Titre photo : < INPUT type = "text" name = "titre" id = "titre" > < BR >
2021-04-28 20:47:11 +02:00
2021-06-12 19:57:59 +02:00
< INPUT type = "reset" id = "enreg" value = "Ajouter" onClick = ajouter_personne_xml("",souris_x,souris_y,"","");lecture_xml(); >
< INPUT type = "reset" value = "Annuler" onClick = document.getElementById("ajout").className="invisible"; >
2021-04-28 20:47:11 +02:00
< / form >
< / div >
< div id = "menu_modif" class = "invisible" >
2021-06-12 19:57:59 +02:00
< div id = "modifier" onClick = "modifier_personne();" > modifier < / div >
2021-04-28 20:47:11 +02:00
< div id = "supprimer" onClick = "supprimer_personne();menu.style.visibility='hidden';" > supprimer< / div >
< div id = "annuler" onClick = "menu.style.visibility='hidden';" > annuler< / div >
< / div >
< script >
2021-06-12 19:57:59 +02:00
var personnes=[],nom=[],nomjf=[],prenom=[],annee=[],note=[],posx=[],posy=[],etx=[],ety=[], can_etiq=[];
var ibac=0, tit={}, titre="", fond=[];
var mode_saisie="true" // mode saisie true, mode modification false
2021-04-28 20:47:11 +02:00
var image = document.getElementById('ima_fond');
var cercle = document.getElementById("cirsvg");
var menu = document.getElementById("menu_modif");
2021-06-12 19:57:59 +02:00
var modif_titre = document.getElementById("nouveau_titre");
2021-04-28 20:47:11 +02:00
var cant = document.createElement("canvas");
2021-06-12 19:57:59 +02:00
document.body.appendChild(cant);
let inputElement = document.getElementById('fichiers');
inputElement.addEventListener('change', (e) => {
lecfic(e.target.files)
}, false);
2021-04-28 20:47:11 +02:00
function lecfic(fichier) {
2021-06-12 19:57:59 +02:00
nb_fichier=fichier.length
var i_xml=1, i_img=0;
if (fichier[0].name.split('.').pop()=="xml") {i_xml=0; i_img=1};
2021-04-28 20:47:11 +02:00
var src=fichier[i_img].name.substring(0,fichier[i_img].name.indexOf("."));
enreg_xml=src+".xml"
enreg_noms=src+"_noms.png"
2021-06-12 19:57:59 +02:00
fichier_xml=fichier[i_xml];
fond=fichier[i_img];
affiche_fond();
2021-04-28 20:47:11 +02:00
2021-06-12 19:57:59 +02:00
if (nb_fichier==1) {creation_data_xml(); lecture_xml(); return} // Un seul fichier sélectionné : l'image à traiter
if (fichier_xml.name.startsWith("haar")) {creation_data_xml(); detection_de_visages();return} // deux fichiers selectionnés : l'image et haarcascade.xml
// deux fichiers selectionnés : l'image et le xml du même nom
2021-04-28 20:47:11 +02:00
var reader = new FileReader();
reader.onload = function(evt) {lecture(evt.target.result);};
reader.readAsText(fichier_xml);
2021-06-12 19:57:59 +02:00
function lecture(text) {
var parser = new DOMParser();
data_xml = parser.parseFromString(text,"text/xml");
lecture_xml();
2021-04-28 20:47:11 +02:00
};
}
2021-06-12 19:57:59 +02:00
// Chargement et affichage de l'image background
function affiche_fond() {
var read_fond = new FileReader();
read_fond.addEventListener("load", function (evt) {
image.src = evt.target.result;
}, false);
read_fond.readAsDataURL(fond);
}
2021-04-28 20:47:11 +02:00
function lecture_xml() {
tit = data_xml.documentElement.getElementsByTagName("titre")[0];
titre=tit.textContent
2021-06-12 19:57:59 +02:00
personnes = data_xml.documentElement.getElementsByTagName("personne");
2021-04-28 20:47:11 +02:00
nb_pers=personnes.length
for (var i = 0; i < nb_pers ; i + + ) {
nom[i] = personnes[i].getElementsByTagName( "nom")[0].textContent;
if (personnes[i].getElementsByTagName( "nom_jeune_fille")[0]) {
2021-06-12 19:57:59 +02:00
nomjf[i] = personnes[i].getElementsByTagName( "nom_jeune_fille")[0].textContent;
}
2021-04-28 20:47:11 +02:00
prenom[i] = personnes[i].getElementsByTagName( "prenom")[0].textContent;
2021-06-12 19:57:59 +02:00
annee[i] = personnes[i].getElementsByTagName( "annee_naiss")[0].textContent;
note[i] = personnes[i].getElementsByTagName( "note")[0].textContent;
2021-04-28 20:47:11 +02:00
posx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posx'].value);
posy[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['posy'].value);
etx[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['etx'].value);
ety[i] = parseFloat(personnes[i].getElementsByTagName( "position")[0].attributes['ety'].value);
}
2021-06-12 19:57:59 +02:00
if (titre!=='') {affiche_titre(titre)}
affiche_etiquette() ;
2021-04-28 20:47:11 +02:00
};
2021-06-12 19:57:59 +02:00
function affiche_titre(titre_photo) {
2021-04-28 20:47:11 +02:00
cant.className="tit";
cant.height=23;
2021-06-12 19:57:59 +02:00
var taille=titre_photo.length;
2021-04-28 20:47:11 +02:00
cant.width=taille*12;
tx = parseFloat(tit.attributes['titx'].value);
ty = parseFloat(tit.attributes['tity'].value);
cant.style.left = tx + "px";
cant.style.top = ty + "px";
titre_ctx = cant.getContext("2d");
titre_ctx.font = '21px Arial';
titre_ctx.fillStyle = 'Maroon';
2021-06-12 19:57:59 +02:00
titre_ctx.fillText(titre_photo, 20, 18);
affiche_etiquette() ;
2021-04-28 20:47:11 +02:00
}
function affiche_etiquette() {
// affichage du texte nom/prénom dans des canvas etiquette
rayon=28
for (var i = 0; i < nb_pers ; i + + ) {
var id="can"+i;
if (document.getElementById(id)) continue ;
var canv = document.createElement("canvas");
canv.id=id;
document.body.appendChild(canv);
can_etiq[i] = document.getElementById(canv.id);
can_etiq[i].className="etiq";
can_etiq[i].height=30;
etiq_ctx = can_etiq[i].getContext("2d");
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
can_etiq[i].width=taille*7+10
2021-06-12 19:57:59 +02:00
if (nomjf[i].replace(/\t/g, '').length>1) {can_etiq[i].height=45};
2021-04-28 20:47:11 +02:00
etiq_ctx.font = '13px Arial';
etiq_ctx.fillStyle = 'chocolate';
can_etiq[i].style.left = etx[i] + "px";
can_etiq[i].style.top = ety[i] + "px";
etiq_ctx.fillText(nom[i], 7, 12);
etiq_ctx.fillText(prenom[i], 7, 25);
if (nomjf[i].length>1) {etiq_ctx.fillText("née : "+nomjf[i], 7, 38)};
};
2021-06-12 19:57:59 +02:00
gestion_souris();
2021-04-28 20:47:11 +02:00
};
function gestion_souris() {
if (titre!=='') { // pour déplacer le titre
cant.addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
cant.addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
}
for (var i = 0; i < nb_pers ; i + + ) { / / pour déplacer les étiquettes nom , prénom . . .
can_etiq[i].addEventListener("mousedown", function(e){this.addEventListener("mousemove", deplace_etiquette);});
can_etiq[i].addEventListener("mouseup", function(e){this.removeEventListener("mousemove", deplace_etiquette);});
};
ima_fond.addEventListener('mousedown', afficher_formulaire); // pour afficher le formulaire de saisie personne
ima_fond.addEventListener('mousemove', tracer_cercle); // pour afficher cercle personne
cercle.addEventListener('contextmenu', function (e) { menu_modif(e); e.preventDefault();}, false); // menu modif personne
};
function deplace_etiquette(e){
e.target.style.top = e.pageY-15+"px";
e.target.style.left = e.pageX-30+"px";
};
function menu_modif(){
menu.style.left = parseFloat(cercle.getAttribute("cx"))+10 +"px";
menu.style.top = parseFloat(cercle.getAttribute("cy"))+40 +"px";
menu.style.visibility="visible";
}
function supprimer_personne() {
misajour_xml();
x = data_xml.getElementsByTagName("personne")[ibac];
x.parentNode.removeChild(x);
for (var i = 0; i < nb_pers ; i + + ) {
x = can_etiq[i];
x.parentNode.removeChild(x);
};
cercle.style.visibility="hidden";
lecture_xml();
}
2021-06-12 19:57:59 +02:00
function creation_data_xml() {
var x, i;
var txt = "";
var text = "< photo > " +
"< titre titx = '50px' tity = '50px' > Titre "+ fond.name + "< / titre > " +
"< date > < / date > " +
"< lieu > < / lieu > " +
"< commentaire > < / commentaire > " +
"< / photo > ";
var parser_face = new DOMParser();
data_xml = parser_face.parseFromString(text,"text/xml");
// documentElement always represents the root node
x = data_xml.documentElement.childNodes;
for (i = 0; i < x.length ; i + + ) {
txt += x[i].nodeName + ": " + x[i].childNodes[0].nodeValue + "< br > ";
}
};
function detection_de_visages() {
// alert pour temporiser
alert("Ok pour continuer")
src = cv.imread(ima_fond);
gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
chargement_haarcascade();
}
function chargement_haarcascade() {
var reader_haar = new FileReader();
reader_haar.onload = function(ev) {
function str2ab(text) {
return new TextEncoder().encode(text);
}
faceCascadeFile = fichier_xml.name;
let data=str2ab(reader_haar.result)
cv.FS_createDataFile('/', faceCascadeFile, data, true, false, false);
detect_faces();
};
reader_haar.readAsText(fichier_xml);
}
function detect_faces() {
let faces = new cv.RectVector();
let faceCascade = new cv.CascadeClassifier();
// load pre-trained classifiers
faceCascade.load(faceCascadeFile);
// detect faces
let msize = new cv.Size(0, 0);
faceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize, msize);
console.log("Il y a "+ faces.size()+" visage(s)")
for (let i = 0; i < faces.size ( ) ; + + i ) {
ajouter_personne_xml("nom_"+parseInt(i)+" ",faces.get(i).x,faces.get(i).y,faces.get(i).width,faces.get(i).height)
}
// cv.imshow('ima_fond', src);
src.delete(); gray.delete(); faceCascade.delete();
faces.delete();
lecture_xml();
;}
function ajouter_personne_xml(nom_face,fx,fy,fw,fh) {
var nomform=nom_face
var nomjfform=""
var prenomform=""
var anneeform=""
var noteform=""
var posxx=fx+fw/2
var posyy=fy+fh/2
var etxx=fx+10
var etyy=fy+fh*2
document.getElementById('ajout').className='invisible';
if (!nom_face) {
posxx=fx
posyy=fy
etxx=fx-30
etyy=fy+80
nomform=document.getElementById("nom").value
nomjfform=document.getElementById("nom_jeune_fille").value
prenomform=document.getElementById("prenom").value
anneeform=document.getElementById("annee").value
noteform=document.getElementById("note").value
}
// création d'un nouvel élément < personne > dans data_xml
var personne_ = data_xml.createElement("personne");
var nom_ = data_xml.createElement("nom");
nom_.appendChild(data_xml.createTextNode(nomform));
var nom_jf_ = data_xml.createElement("nom_jeune_fille");
nom_jf_.appendChild(data_xml.createTextNode(nomjfform));
var prenom_ = data_xml.createElement("prenom");
prenom_.appendChild(data_xml.createTextNode(prenomform));
var annee_ = data_xml.createElement("annee_naiss");
annee_.appendChild(data_xml.createTextNode(anneeform));
var note_ = data_xml.createElement("note");
note_.appendChild(data_xml.createTextNode(noteform));
var position_ = data_xml.createElement("position");
position_.setAttribute("posx", posxx);
position_.setAttribute("posy", posyy);
position_.setAttribute("etx", etxx);
position_.setAttribute("ety", etyy);
personne_.appendChild(nom_);
personne_.appendChild(nom_jf_);
personne_.appendChild(prenom_);
personne_.appendChild(annee_);
personne_.appendChild(note_);
personne_.appendChild(position_);
data_xml.getElementsByTagName("photo")[0].appendChild(personne_)
};
function modifier_personne() {
mode_saisie="false";
afficher_formulaire(this);
document.getElementById('nom').setAttribute('value', nom[ibac]);
document.getElementById('nom_jeune_fille').setAttribute('value', nomjf[ibac]);
document.getElementById('prenom').setAttribute('value', prenom[ibac]);
document.getElementById('annee').setAttribute('value', annee[ibac]);
document.getElementById('note').setAttribute('value', note[ibac]);
document.getElementById('titre').setAttribute('value', titre);
menu.style.visibility='hidden';
document.getElementById("enreg").style.visibility="hidden";
alert("Fonction en cours de développement")
};
2021-04-28 20:47:11 +02:00
function position_souris(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
};
function tracer_cercle(e) {
document.getElementsByTagName("svg")[0].setAttribute('height', image.naturalHeight);
document.getElementsByTagName("svg")[0].setAttribute('width',image.naturalWidth);
var pos_x=position_souris(ima_fond, e).x;
var pos_y=position_souris(ima_fond, e).y;
for (var i = 0; i < nb_pers ; i + + ) {
var dx = posx[i] - pos_x;
var dy = posy[i] - pos_y;
var dist2 = dx * dx + dy * dy;
var rayon2 = rayon * rayon;
if (dist2 < rayon2 ) {
ibac=i
can_etiq[i].style.background = "palegreen"
cercle.setAttribute("cx",posx[i]);
cercle.setAttribute("cy",posy[i]);
cercle.setAttribute("r",rayon);
cercle.style.visibility="visible";
// grossir ou diminuer la taille du cercle
// cercle.addEventListener("wheel", function(e) {
// rayon=rayon + (e.deltaY>0 ? -1 : +1);
// cercle.setAttribute("r",rayon );
// } , false);
return
}
};
cercle.style.visibility="hidden";
2021-06-12 19:57:59 +02:00
if (nb_pers!=0) {can_etiq[ibac].style.backgroundColor = "oldlace";}
2021-04-28 20:47:11 +02:00
};
function afficher_formulaire(e) {
2021-06-12 19:57:59 +02:00
var formul=document.getElementById('ajout')
2021-04-28 20:47:11 +02:00
souris_x = position_souris(ima_fond, e).x ;
souris_y = position_souris(ima_fond, e).y;
2021-06-12 19:57:59 +02:00
if (souris_y-document.getElementById('ajout').height< 0 ) { sourisy = 50};
formul.style.top=souris_y+40+"px";
formul.style.left=souris_x-80+"px";
2021-04-28 20:47:11 +02:00
setTimeout(function () { document.getElementById("nom").focus(); },10);
2021-06-12 19:57:59 +02:00
formul.className='visible';
2021-04-28 20:47:11 +02:00
2021-06-12 19:57:59 +02:00
// document.getElementById('ajout_personne').reset(); // ne fonctioone pas !
if (mode_saisie) {
document.getElementById('nom').setAttribute('value', "");
document.getElementById('nom_jeune_fille').setAttribute('value', "");
document.getElementById('prenom').setAttribute('value', "");
document.getElementById('annee').setAttribute('value', "");
document.getElementById('note').setAttribute('value', "");
}
mode_saisie="true";
2021-04-28 20:47:11 +02:00
};
2021-06-12 19:57:59 +02:00
2021-04-28 20:47:11 +02:00
function misajour_xml(){
tit.setAttribute("titx",cant.style.left);
tit.setAttribute("tity",cant.style.top);
for (var i = 0; i < nb_pers ; i + + ) {
position=data_xml.getElementsByTagName( "position")[i];
position.setAttribute("etx",can_etiq[i].style.left);
position.setAttribute("ety",can_etiq[i].style.top);
};
lecture_xml();
} ;
function enregistrer_fichier(fichier) {
misajour_xml()
var texte_xml=(new XMLSerializer()).serializeToString(data_xml)
2021-06-12 19:57:59 +02:00
texte_xml=formatXml(texte_xml)
2021-04-28 20:47:11 +02:00
var blob = new Blob([texte_xml], {type: "text/plain;charset=utf-8"});
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, fichier);
} else {
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', fichier);
a.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(texte_xml));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}
2021-06-12 19:57:59 +02:00
function formatXml(xml, tab) { // tab = optional indent value, default is tab (\t)
var formatted = '', indent= '';
tab = tab || '\t';
xml.split(/>\s*< /).forEach(function(node) {
if (node.match( /^\/\w/ )) indent = indent.substring(tab.length); // decrease indent by one 'tab'
formatted += indent + '< ' + node + '>\r\n';
if (node.match( /^< ?\w[^>]*[^\/]$/ )) indent += tab; // increase indent
});
return formatted.substring(1, formatted.length-3);
}
2021-04-28 20:47:11 +02:00
function image_finale() {
misajour_xml()
var decalx=5;
var decaly=29;
var can_imf = document.createElement("canvas");
document.body.appendChild(can_imf);
imf_ctx = can_imf.getContext("2d");
can_imf.width=ima_fond.width;
can_imf.height=ima_fond.height;
imf_ctx.drawImage(ima_fond,0,0)
if (titre!=='') {
var taille=titre.length;
hauteur=25
roundedRect(imf_ctx,tx-decalx,ty-decaly,taille*11,hauteur,5,'lightyellow','yellow');
imf_ctx.drawImage(cant, tx-decalx, ty-decaly)
};
for (var i = 0; i < nb_pers ; i + + ) {
var taille=Math.max(nom[i].length,prenom[i].length,nomjf[i].length+5);
hauteur=30
2021-06-12 19:57:59 +02:00
if (nomjf[i].replace(/\t/g, '').length>1) {hauteur=45};
// if (!nomjf[i].charCodeAt(1)==9) {hauteur=45};
2021-04-28 20:47:11 +02:00
roundedRect(imf_ctx,etx[i]-decalx,ety[i]-decaly,taille*7+10,hauteur,15,'oldlace','blue');
imf_ctx.drawImage(can_etiq[i],etx[i]-decalx,ety[i]-decaly)
}
var a = document.createElement('a');
if (a.download === '');
a.setAttribute('download', enreg_noms);
a.setAttribute('href', can_imf.toDataURL("image/png").replace("image/png", "image/octet-stream"));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
document.body.removeChild(can_imf);
function roundedRect(ctx, x, y, width, height, radius ,couleur_fond ,couleur_trait) {
ctx.beginPath();
ctx.strokeStyle = couleur_trait;
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.closePath();
ctx.fillStyle = couleur_fond;
ctx.fill();
ctx.stroke();
}
}
< / script >
2021-06-12 19:57:59 +02:00
< script >
function onOpenCvReady() {
document.getElementById('status').innerHTML = 'OpenCV.js est chargé !';
}
< / script >
< script src = "opencv.js" onload = "onOpenCvReady();" type = "text/javascript" > < / script >
2021-04-28 20:47:11 +02:00
< / body >
< / html >