   
   const aPages = { // Formats normalisés des pages avec dimensions en cm
   	   A6: [ 10.5, 14.8 ],
   	   A5: [ 14.8, 21.0 ],
   	   A4: [ 21.0, 29.7 ],
   	   A3: [ 29.7, 42.0 ],
   	   A2: [ 42.0, 59.4 ],
   	   A1: [59.4, 84.1 ],
   	   A0: [84.1, 118.9 ]
   };
   const ppi = 72.0 / 2.54;			// Conversion pt / cm
   const sqrt2 = Math.sqrt(2);
   const mrg6 = 10.0 * ppi / 8.0;		// 10 cm en A0
   
   function margeFooter(opt) {
   	   switch(opt.pageSize) {
   	   case 'A6': return mrg6;
   	   case 'A5': return (mrg6 * sqrt2);
   	   case 'A4': return (mrg6 * 2);
   	   case 'A3': return (mrg6 * 2 * sqrt2);
   	   case 'A2': return (mrg6 * 4);
   	   case 'A1': return (mrg6 * 4 * sqrt2);
   	   case 'A0': return (mrg6 * 8);
   	   default: return opt.margin;
   	   }
   }
   
   function optimiserTailleImage(params) {
   	   let pgWidth = aPages[params.pageSize][0]; 	// Largeur de la page en cm
   	   let imWidth = params.size;					// Largeur d'une image en pt  	   
   	   let ppw = pgWidth * ppi;						// Largeur de la page en pt
   	   // Marge par defaut : 1cm (en pt)
   	   params.marge = (params.marge >0) ? params.marge : Math.round(ppi);	
   	   let margins = params.marge * 2;				// Total marges latérales : 2x marge
   	   // espace entre deux images : par défaut la moitié de la marge
   	   let gutter = (params.gouttiere >0) ? params.gouttiere: Math.round(ppi / 2);
   	   // largeur utile de toutes les images d'une ligne
   	   let uppw = ppw - margins - ( gutter * (params.nbCol -1));
   	   let szImg = Math.floor(uppw / params.nbCol);
   	   // Marges à appliquer globalement à la table
   	   let tabMargin = Math.round((uppw - (szImg * params.nbCol)) / 2);
   	   return [szImg, tabMargin];
   }
   
   function calculerLargeur(opt) {
   	  let pgWidth = aPages[opt.pageSize][0]; 		// Largeur de la page en cm
   	  let ppw = pgWidth * ppi;				// Largeur totale de la page en pt
   	  console.log('pgWidth = '+ pgWidth + ' ppw = ' + ppw + ' marge = ' + opt.marge);
   	  return (ppw - (2 * opt.marge));		// Largeur sans les marges
   }
   
   function equalWidthColumns(nbcol) {
   	   var pattern = [];
   	   for(let i=0; i<nbcol; i++) pattern.push("*");
   	   return pattern;
   }
   
   function completerArbre(arbre, params) {
   	   arbre.soustitre = params.soustitre;
   	   if(params.pretexte.trim().length) {
   	   	   arbre.pretexte = params.pretexte;
   	   }
   	   if(params.posttexte.trim().length) {
   	   	   arbre.posttexte = params.posttexte;
   	   }
   	   return arbre;
   }
   
   function preparerNoeud(arbre,level,params) {
   	  let style = "header" + level;
   	  const contenu = [ { "style": style, "text": arbre.titre } ];
   	  
   	  // Sous-titre optionnel
   	  if(Object.hasOwn(arbre,'soustitre')) {
   	  	  let style2 = "s"+ style;
   	  	  contenu.push({ "style": style2, "text": arbre.soustitre });
   	  }
   	  // Texte pré-contenu
   	  if(Object.hasOwn(arbre,'pretexte')) {	
   	  	  contenu.push({ "style": 'pretexte', "text": arbre.pretexte });
   	  }   	  
   	  // Traitement des feuilles (niveau courant)
   	  if(Object.hasOwn(arbre, 'feuilles')) {
   	  	  contenu.push(preparerFeuilles(arbre.feuilles,params));
   	  }
   	  // Traitement des noeuds (niveau inférieur)
   	  // La structure des données est arborescence mais la structure du document est à plat
   	  // Il faut donc fusionner le tableau revenant du niveau inférieur avec celui du niveau courant
   	  // et ne pas générer de sous-tableau
   	  if(Object.hasOwn(arbre,'noeuds')) {
   	  	  arbre.noeuds.forEach(function(item,index) {
   	  	  		contenu.push(...preparerNoeud(item,level+1,params));  
   	  	  });
   	  }
   	  // Texte post-contenu
   	  if(Object.hasOwn(arbre,'posttexte')) {	
   	  	  contenu.push({ "style": 'posttexte', "text": arbre.posttexte });
   	  } 
   	  return contenu;
    }
    
   function preparerFeuilles(feuilles,params) {
   	   var branche = {
   	   	   layout: "noBorders",
   	   	   style: "corps",
   	   	   margin: [params.margeTable,0,params.margeTable,0],
   	   	   table: {
   	   	   	   headerRows: 0,
   	   	   	   widths: equalWidthColumns(params.nbCol),
   	   	   	   dontBreakRows: true,
   	   	   	   body: preparerBody(feuilles,params)
   	   	   }
   	   };
   	   return branche;
   }
   
   function preparerBody(feuilles,params) {
   	   var body = [], nymph = [];
   	   var leaves = feuilles;
   	   // On décompose le tableau de feuilles en un tableau de tableaux
   	   // Chaque sous-tableau a (au plus) params.nbCol éléments
   	   while(leaves.length >0) nymph.push(leaves.splice(0,params.nbCol));
   	   // On génère les instructions de mise en forme pour chaque élément
   	   // Un élément contient une image, un titre et un sous-titre
   	   nymph.forEach(function(item, index) {
   	   		   let line = item.map((one) => [
   	   		   		   { "image": one.image, "fit": [params.size, params.size] },
   	   		   		   { "text": one.titre, "style": ['titreImg', 'gauche','gras'] },
   	   		   		   { "text": one.soustitre, "style": ['soustitreImg', 'gauche','italique'] }
   	   		   ]);
   	   		   // On complète les sous-tableaux n'ayant pas exactement le bon nombre d'éléments
   	   		   if(line.length < params.nbCol) {
   	   		   	   for(let i= line.length ; i< params.nbCol; i++) line.push(" ");
   	   		   }
   	   		   // Chaque sous-tableau génère une ligne de la future table
   	   		   body.push(line);
   	   });
   	   // On retourne le contenu complet de la table
   	   return body;
   }
   
   var pageBreakLogic = function(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
   	   if(followingNodesOnPage.length == 0) {
   	   	   if(Object.hasOwn(currentNode,'style')) {
   	   	   	   // Conditions sur les styles
   	   	   	   let styles = Array.isArray(currentNode.style) ? currentNode.style : [ currentNode.style ];
   	   	   	   // Pas de titre en fin de page
   	   	   	   if(styles.includes('header1')) return true;
   	   	   	   if(styles.includes('header2')) return true;
   	   	   }
   	   	   // Conditions hors styles
   	   }
   	   // other conditions here ?
   	   return false;
   };

   function changerPolice(styles,police) {
   	   for(var style in styles) {
   	   	   if(styles.hasOwnProperty(style) && styles[style].hasOwnProperty('font')) {
   	   	   	   styles[style].font = police;
   	   	   }
   	   }
   	   return styles;
   }
   	   	   	   
  
 
   