/*************************************************************************************
* Ce script a pour but de mettre sur une planche contact toutes les photos           *
* (maximum : 36) trouvées dans un dossier, comme cela se faisait en argentique.      *
*  Il peut s'agir de diapos couleur ou N&B ou de négatifs couleur ou N&B             *
*         Michel Rohan (Annecy - France) - le 18/10/2019 - Open Source               *
**************************************************************************************

// *************************DEBUT DE PROGRAMME **************************************/

#target photoshop 					// MAC Finder ou WINDOWS Explorer : on autorise le double clic
app.bringToFront(); 				// On fait passer Photoshop au 1er plan
displayDialogs = DialogModes.NO;    // Désactivation des boîtes de dialogue

	
// On mémorise les unités trouvées dans les préférences de l'utilisateur...
var regleUnite = app.preferences.rulerUnits;
var typeUnite = app.preferences.typeUnits;
	
// Déclaration des variables
var couleur=true;
var positif=true;
var largeur=0;
var hauteur=0;
var adresse="";
var planche="";
var fileExists=false;
var cancel=false;
var nbFiles = 1;

var psd_Options  = new PhotoshopSaveOptions();  
psd_Options.layers  = true; 
psd_Options.embedColorProfile = true; 
psd_Options.annotations = true; 
psd_Options.alphaChannels = true; 
psd_Options.spotColors = true;

var jpeg_Options = new JPEGSaveOptions();
jpeg_Options.embedColorProfile = true;
jpeg_Options.formatOptions = FormatOptions.STANDARDBASELINE;
jpeg_Options.matte = MatteType.NONE;
jpeg_Options.quality = 12;

var ligne = new Array();
ligne[0] = 511;
ligne[1] = 2213;
ligne[2] = 3883;
ligne[3] = 5585;
ligne[4] = 7203;
ligne[5] = 8905;
//les bandes ne sont pas alignées en X. La variable 'offset' correspond au décalage en pixels par rapport à la bande la plus à gauche (1ère)
var offset = new Array();
offset[0] = 0;
offset[1] = 60;
offset[2] = 28;
offset[3] = 55;
offset[4] = 8;
offset[5] = 68;

// Mode d'emploi
var modeEmploi = "";
modeEmploi += "1 - Vos photos peuvent être verticales ou horizontales, en couleur ou en N&B, peu importe. Mais elles doivent être au ratio 3:2 (24x36).";
modeEmploi += "\n\n2 - Par défaut, le programme est paramétré pour faire des planches contact en diapositive couleur, mais vous pouvez aussi les faire en N&B et/ou en négatif.";
modeEmploi += "\n\n3 - Vous ne devez pas avoir de photos converties en valeurs de gris dans vos photos.";
modeEmploi += "\n\n4 - Le mockup \"Film.psd\" peut se trouver n'importe où sur votre disque dur.";
modeEmploi += "\n\n5 - La planche contact est créée dans le format \".PSD\" par défaut. Si vous choisissez l'option de sortie JPEG, l'image sera aplatie avant la sauvegarde.";

// Interface frontale
var dlgBox = new Window('dialog', 'Planche contact', {x:0, y:0, width:695, height:190}); 

// Cadre option couleur ou N&B
var panCoul = dlgBox.add('panel', {x:10, y:10, width:330, height:80}, 'Couleur / N&B');
var radio1 = panCoul.add ("radiobutton", {x:11, y:15, width:100, height:25}, "Couleur");
var radio2 = panCoul.add ("radiobutton", {x:11, y:40, width:100, height:25}, "Noir & Blanc");
radio1.value = true;

// Cadre option positif ou négatif
var panType = dlgBox.add('panel', {x:350, y:10, width:335, height:80}, 'Positif / Négatif');
var radio3 = panType.add ("radiobutton", {x:14, y:15, width:100, height:25}, "Positif");
var radio4 = panType.add ("radiobutton", {x:14, y:40, width:100, height:25}, "Négatif");
radio3.value = true;

// Boutons radio format de sortie
format = dlgBox.add('statictext',{x:210, y:105, width:120, height:21},"Format de sortie : "); 
var radio5 = dlgBox.add ("radiobutton", {x:320, y:100, width:100, height:25}, "PSD");
var radio6 = dlgBox.add ("radiobutton", {x:380, y:100, width:100, height:25}, "JPEG");
radio5.value = true;

// Bouton Exécuter
button1 = dlgBox.add ("button",  {x:150, y:140, width:130, height:25}, "Exécuter");
button1.onClick = main;

// Bouton mode d'emploi
button1 = dlgBox.add ("button",  {x:290, y:140, width:130, height:25}, "Mode d'emploi");
button1.onClick = notice_click;

// Bouton pour quitter
button3 = dlgBox.add ("button",  {x:430, y:140, width:130, height:25}, "Quitter");
button3.onClick = quitter_click;

// On centre le frontal sur l'écran et on l'affiche
dlgBox.center();
dlgBox.show();

// *************************** FIN DE PROGRAMME ***************************************

function main() {  
	// L'utilisateur a interrompu le script
	if (cancel==true) {
		alert("Arrêt du traitement.");
		restauration();
		return;
	}

	// On va travailler en pixels.
	app.preferences.rulerUnits = Units.PIXELS;
	app.preferences.typeUnits = TypeUnits.PIXELS;
	
	var formatFile = 1; // PSD
	if (radio6.value==true) {formatFile = 2} // JPEG

	// Paramètres choisis par l'utilisateur
	couleur=true;
	if (radio2.value==true) couleur=false;
	positif=true;
	if (radio4.value==true) positif=false;

	// On n'a plus besoin de l'interface graphique, on la masque et on charge la planche contact
	dlgBox.hide();
	
	// On sélectionne le dossier contenant les images à traiter et le script	
	var inputFolder = Folder.selectDialog("Sélectionnez le dossier contenant les photos au format JPEG");
	var fileList = inputFolder.getFiles(/\.(jpg|jpeg|)$/i);

	// Si le dossier ne contient pas d'image on arrête le process
	if (fileList.length==0)	{
		alert("Ce dossier ne contient pas de fichiers au format JPEG. Veuillez relire les instructions.")
		restauration();
		return;
	}
	
	// On crée le dossier de sauvegarde s'il n'existe pas
	var outputFolder = Folder(inputFolder.path + "/" + inputFolder.name + "/Sauvegarde");
	if (!outputFolder.exists) outputFolder.create();

	//	On charge le mockup (Film.psd)
	var mockup = File.openDialog("Ouvrez le fichier Film.psd.","Film.psd");
	
	// Le mockup n'a pas été retrouvé
	if(mockup==null) {
		restauration();
		return;
	}
	
	app.open(mockup);
	
	// Diapo couleur
	if (positif==true && couleur==true) { // Diapo couleur 
		app.activeDocument.layers[2].remove();
		app.activeDocument.layers[2].remove();
		app.activeDocument.layers[2].remove();
	}

	// Diapo Noir & Blanc
	if (positif==true && couleur==false) { // Diapo Noir & Blanc 
		app.activeDocument.layers[1].remove();
		app.activeDocument.layers[2].remove();
		app.activeDocument.layers[2].remove();
	}
	
	// Négatif couleur
	if (positif==false && couleur==true) { // Diapo Noir & Blanc 
		app.activeDocument.layers[1].remove();
		app.activeDocument.layers[1].remove();
		app.activeDocument.layers[2].remove();
	}
	
	// Négatif Noir & Blanc
	if (positif==false && couleur==false) { // Diapo Noir & Blanc 
		app.activeDocument.layers[1].remove();
		app.activeDocument.layers[1].remove();
		app.activeDocument.layers[1].remove();
	}
	// On retire le calque "Splash"
	app.activeDocument.layers[0].remove();

	// Traitement des photos
	largeur=0;
	hauteur=0;
	
	for (var i= 0;i<fileList.length;i++) {
		// On ouvre le document
		var docRef = open(fileList[i]);
		largeur = docRef.width;
		hauteur = docRef.height;
		// Si le N&B est choisi on dessature l'image pour avoir des contre-types en N&B
		if (couleur==false) desaturation()
		if (positif==false) inversion()	
		// Si la photo est verticale, on la met à l'horizontale
		if (hauteur>=largeur) docRef.rotateCanvas(270);
		// On retaille le document en 1080 pixels de haut et 72 dpi			
		docRef.resizeImage(null,UnitValue(1080,"px"),72,ResampleMethod.BICUBIC);
		// On sélectionne l'images et on la copie en mémoire vive
		docRef.selection.selectAll();
		docRef.selection.copy();
		// On referme la vignette puisqu'on n'en a plus besoin et on la copie sur la planche contact
		docRef.close(SaveOptions.DONOTSAVECHANGES);
		var docRef = app.activeDocument;
		//On se positionne au sommet de la pile des calques
		docRef.activeLayer = docRef.layers[0];
		docRef.paste();
		// On renomme le calque
		docRef.activeLayer.name = "Photo n° "+(i+1);
		// On place la photo au bon endroit
		var quotient = (i+1)/6;
		if (quotient==parseInt(quotient)) {
			y = quotient;
			x = 6;
		}
		else {
			y= parseInt(quotient) +1;
			x = i+1-(y-1)*6;
		}
		x = 1740*(x-1) + offset[y-1]+58;
		y = ligne[y-1];
		moveLayer(docRef.activeLayer,x,y);
	}

	var dateObj = new Date();
    var annee = dateObj.getFullYear().toString().substr(-2);
    var mois = ("0" + (dateObj.getMonth() + 1)).slice(-2); 
    var jour = ("0" + dateObj.getDate()).slice(-2);
    var heure = ("0" + (dateObj.getHours())).slice(-2);
    var minute= ("0" + (dateObj.getMinutes())).slice(-2);
	var seconde= ("0" + (dateObj.getSeconds())).slice(-2);
	var identifier = annee+mois+jour+heure+minute+seconde;

	if (formatFile==2) { // JPEG
		docRef.flatten();
		docName = "img_" + identifier + ".jpg";
		docRef.saveAs(File(outputFolder + '/' + docName), jpeg_Options, true );
	}
	else {				// PSD
		docName = "img_" + identifier + ".psd";
		docRef.saveAs(File(outputFolder + '/' + docName), psd_Options, true );
	}
	docRef.close(SaveOptions.DONOTSAVECHANGES);

	alert("Traitement terminé. Votre planche contact a été sauvegardée dans le dossier " + outputFolder);
	restauration();
}



// FIN DE PROGRAMME ***************************************************************************************

function notice_click() 
{
    alert(modeEmploi);
}

function quitter_click() 
{
	dlgBox.hide();
	return;
}

function inversion()
{
	var idInvr = charIDToTypeID( "Invr" );
	executeAction( idInvr, undefined, DialogModes.NO );
}

function moveLayer(fLayer,X,Y) {
  var Position = fLayer.bounds;
  Position[0] = X - Position[0];
  Position[1] = Y - Position[1];

  fLayer.translate(-Position[0],-Position[1]);
}

function desaturation()
{
	// =======================================================
	var idHStr = charIDToTypeID( "HStr" );
    var desc41 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID( "presetKind" );
    var idpresetKindType = stringIDToTypeID( "presetKindType" );
    var idpresetKindCustom = stringIDToTypeID( "presetKindCustom" );
    desc41.putEnumerated( idpresetKind, idpresetKindType, idpresetKindCustom );
    var idClrz = charIDToTypeID( "Clrz" );
    desc41.putBoolean( idClrz, false );
    var idAdjs = charIDToTypeID( "Adjs" );
	var list1 = new ActionList();
	var desc42 = new ActionDescriptor();
	var idH = charIDToTypeID( "H   " );
	desc42.putInteger( idH, 0 );
	var idStrt = charIDToTypeID( "Strt" );
	desc42.putInteger( idStrt, -100 );
	var idLght = charIDToTypeID( "Lght" );
	desc42.putInteger( idLght, 0 );
	var idHsttwo = charIDToTypeID( "Hst2" );
	list1.putObject( idHsttwo, desc42 );
    desc41.putList( idAdjs, list1 );
executeAction( idHStr, desc41, DialogModes.NO );
}

function restauration() {
	// On restaure l'unité trouvée au départ dans les préférences de l'utilisateur
	app.preferences.rulerUnits = regleUnite;
	app.preferences.typeUnits = typeUnite;
}





