Ajoute le plugin Acrobat Pro d'imposition (acrobat-plugin/)
Suite d'imposition professionnelle en Folder-Level Scripts JS (7 modules + verification de licence Vision), avec un plugin natif hybride optionnel (WinINet + Registre) pour deplacer la verification de licence en code compile. Installeur install.bat sur le meme modele que celui du projet desktop (git portable, detection automatique des dossiers Acrobat).
This commit is contained in:
258
acrobat-plugin/install.bat
Normal file
258
acrobat-plugin/install.bat
Normal file
@@ -0,0 +1,258 @@
|
||||
@echo off
|
||||
chcp 65001 >nul 2>&1
|
||||
setlocal EnableDelayedExpansion
|
||||
title Imposition Professionnelle (Acrobat) — Installation
|
||||
|
||||
set "APP_NAME=Imposition Professionnelle (plugin Acrobat)"
|
||||
set "INSTALL_DIR=%LOCALAPPDATA%\CopydevImposingAcrobat"
|
||||
set "REPO_DIR=%INSTALL_DIR%\repo"
|
||||
set "GITEA_REPO=https://git.copydev.fr/jules/copydev-imposing-tool.git"
|
||||
set "GIT_URL=https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.2/MinGit-2.47.1.2-64-bit.zip"
|
||||
|
||||
:: ============================================================
|
||||
:MENU
|
||||
cls
|
||||
echo ============================================================
|
||||
echo %APP_NAME%
|
||||
echo ============================================================
|
||||
echo.
|
||||
echo 1. Installer
|
||||
echo 2. Mettre a jour
|
||||
echo 3. Lancer Acrobat
|
||||
echo 4. Desinstaller
|
||||
echo 5. Quitter
|
||||
echo.
|
||||
set "CHOIX="
|
||||
set /p "CHOIX=Votre choix [1-5] : "
|
||||
|
||||
if "%CHOIX%"=="1" goto INSTALL
|
||||
if "%CHOIX%"=="2" goto UPDATE
|
||||
if "%CHOIX%"=="3" goto LAUNCH
|
||||
if "%CHOIX%"=="4" goto UNINSTALL
|
||||
if "%CHOIX%"=="5" goto FIN
|
||||
echo Choix invalide.
|
||||
timeout /t 2 >nul
|
||||
goto MENU
|
||||
|
||||
:: ============================================================
|
||||
:: GIT (portable si absent du systeme)
|
||||
:: ============================================================
|
||||
:TROUVER_GIT
|
||||
set "GIT_CMD="
|
||||
where git >nul 2>&1
|
||||
if %ERRORLEVEL%==0 (
|
||||
set "GIT_CMD=git"
|
||||
exit /b 0
|
||||
)
|
||||
if exist "%INSTALL_DIR%\git\cmd\git.exe" (
|
||||
set "GIT_CMD=%INSTALL_DIR%\git\cmd\git.exe"
|
||||
exit /b 0
|
||||
)
|
||||
echo Telechargement de Git portable...
|
||||
if not exist "%INSTALL_DIR%\temp" mkdir "%INSTALL_DIR%\temp"
|
||||
if not exist "%INSTALL_DIR%\git" mkdir "%INSTALL_DIR%\git"
|
||||
powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Invoke-WebRequest -Uri '%GIT_URL%' -OutFile '%INSTALL_DIR%\temp\git.zip' -UseBasicParsing"
|
||||
if not exist "%INSTALL_DIR%\temp\git.zip" (
|
||||
echo [ERREUR] Echec telechargement Git
|
||||
exit /b 1
|
||||
)
|
||||
powershell -Command "Expand-Archive -Force '%INSTALL_DIR%\temp\git.zip' '%INSTALL_DIR%\git'"
|
||||
del "%INSTALL_DIR%\temp\git.zip" 2>nul
|
||||
if not exist "%INSTALL_DIR%\git\cmd\git.exe" (
|
||||
echo [ERREUR] git.exe introuvable apres extraction
|
||||
exit /b 1
|
||||
)
|
||||
set "GIT_CMD=%INSTALL_DIR%\git\cmd\git.exe"
|
||||
exit /b 0
|
||||
|
||||
:: ============================================================
|
||||
:: Detection des dossiers JavaScripts d'Acrobat (un par version
|
||||
:: installee, ex: DC, 2020, 2024...). Cree le dossier si absent
|
||||
:: (ne necessite pas de droits admin : c'est sous %APPDATA%).
|
||||
:: ============================================================
|
||||
:TROUVER_DOSSIERS_ACROBAT
|
||||
set "NB_DOSSIERS=0"
|
||||
if not exist "%APPDATA%\Adobe\Acrobat" (
|
||||
exit /b 1
|
||||
)
|
||||
for /d %%D in ("%APPDATA%\Adobe\Acrobat\*") do (
|
||||
if not exist "%%D\JavaScripts" mkdir "%%D\JavaScripts"
|
||||
set /a NB_DOSSIERS+=1
|
||||
set "DOSSIER_JS_!NB_DOSSIERS!=%%D\JavaScripts"
|
||||
)
|
||||
if "%NB_DOSSIERS%"=="0" exit /b 1
|
||||
exit /b 0
|
||||
|
||||
:: ============================================================
|
||||
:: INSTALLATION / MISE A JOUR (meme logique : on clone si absent,
|
||||
:: on pull sinon, puis on recopie les fichiers a jour)
|
||||
:: ============================================================
|
||||
:INSTALL
|
||||
cls
|
||||
echo ============================================================
|
||||
echo INSTALLATION de %APP_NAME%
|
||||
echo ============================================================
|
||||
goto DEPLOIEMENT
|
||||
|
||||
:UPDATE
|
||||
cls
|
||||
echo ============================================================
|
||||
echo MISE A JOUR de %APP_NAME%
|
||||
echo ============================================================
|
||||
goto DEPLOIEMENT
|
||||
|
||||
:DEPLOIEMENT
|
||||
echo.
|
||||
if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%"
|
||||
|
||||
echo [1/4] Git...
|
||||
call :TROUVER_GIT
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
pause
|
||||
goto MENU
|
||||
)
|
||||
echo [OK]
|
||||
|
||||
echo.
|
||||
echo [2/4] Telechargement du code (acrobat-plugin/)...
|
||||
if exist "%REPO_DIR%\.git" (
|
||||
pushd "%REPO_DIR%"
|
||||
"%GIT_CMD%" fetch origin
|
||||
"%GIT_CMD%" pull origin master
|
||||
popd
|
||||
) else (
|
||||
if exist "%REPO_DIR%" rmdir /s /q "%REPO_DIR%"
|
||||
"%GIT_CMD%" clone "%GITEA_REPO%" "%REPO_DIR%"
|
||||
)
|
||||
if not exist "%REPO_DIR%\acrobat-plugin\src\Imposition-00-Core.js" (
|
||||
echo [ERREUR] Code source introuvable apres clonage/mise a jour
|
||||
pause
|
||||
goto MENU
|
||||
)
|
||||
echo [OK]
|
||||
|
||||
echo.
|
||||
echo [3/4] Detection d'Acrobat et copie des scripts...
|
||||
call :TROUVER_DOSSIERS_ACROBAT
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo [ERREUR] Aucune installation d'Acrobat trouvee sous %APPDATA%\Adobe\Acrobat
|
||||
echo Verifiez qu'Acrobat Pro (pas seulement Reader) est installe.
|
||||
pause
|
||||
goto MENU
|
||||
)
|
||||
for /l %%i in (1,1,%NB_DOSSIERS%) do (
|
||||
echo -^> !DOSSIER_JS_%%i!
|
||||
copy /y "%REPO_DIR%\acrobat-plugin\src\*.js" "!DOSSIER_JS_%%i!\" >nul
|
||||
)
|
||||
echo [OK] Scripts copies dans %NB_DOSSIERS% dossier^(s^) Acrobat
|
||||
|
||||
echo.
|
||||
echo [4/4] Plugin natif (verification de licence)...
|
||||
if exist "%REPO_DIR%\acrobat-plugin\native\dist\ImposingLicence.api" (
|
||||
set "PLUGIN_DEST=%APPDATA%\Adobe\Acrobat"
|
||||
for /d %%D in ("%APPDATA%\Adobe\Acrobat\*") do (
|
||||
if not exist "%%D\Plug_ins3" mkdir "%%D\Plug_ins3"
|
||||
copy /y "%REPO_DIR%\acrobat-plugin\native\dist\ImposingLicence.api" "%%D\Plug_ins3\" >nul
|
||||
echo -^> %%D\Plug_ins3\ImposingLicence.api
|
||||
)
|
||||
echo [OK] Plugin natif copie
|
||||
echo [!] Dossier "Plug_ins3" a verifier : c'est l'emplacement usuel des
|
||||
echo plugins utilisateur sans droits admin, mais a confirmer selon
|
||||
echo votre version d'Acrobat.
|
||||
) else (
|
||||
echo [INFO] Aucun .api precompile trouve dans native\dist\
|
||||
echo Le plugin natif est optionnel : la suite fonctionne en JS seul,
|
||||
echo avec une verification de licence plus simple ^(voir documentation^).
|
||||
echo Pour l'activer, compilez native\PluginMain.cpp ^(SDK Acrobat + VS^)
|
||||
echo et placez le .api resultant dans native\dist\ImposingLicence.api
|
||||
echo avant de relancer cet installeur.
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ============================================================
|
||||
echo TERMINE
|
||||
echo ============================================================
|
||||
echo.
|
||||
echo Redemarrez Acrobat Pro pour charger les scripts.
|
||||
echo Menu attendu : Edition ^> Imposition Pro
|
||||
echo.
|
||||
set /p "LAUNCH=Lancer Acrobat maintenant ? [O/N] : "
|
||||
if /i "!LAUNCH!"=="O" call :LANCER_ACROBAT
|
||||
pause
|
||||
goto MENU
|
||||
|
||||
:: ============================================================
|
||||
:: LANCER ACROBAT
|
||||
:: ============================================================
|
||||
:LAUNCH
|
||||
cls
|
||||
echo ============================================================
|
||||
echo LANCEMENT D'ACROBAT
|
||||
echo ============================================================
|
||||
echo.
|
||||
call :LANCER_ACROBAT
|
||||
timeout /t 2 >nul
|
||||
goto MENU
|
||||
|
||||
:LANCER_ACROBAT
|
||||
where acrobat >nul 2>&1
|
||||
if %ERRORLEVEL%==0 (
|
||||
start "" acrobat
|
||||
exit /b 0
|
||||
)
|
||||
if exist "%ProgramFiles(x86)%\Adobe\Acrobat DC\Acrobat\Acrobat.exe" (
|
||||
start "" "%ProgramFiles(x86)%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
|
||||
exit /b 0
|
||||
)
|
||||
if exist "%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe" (
|
||||
start "" "%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
|
||||
exit /b 0
|
||||
)
|
||||
echo [!] Executable Acrobat introuvable automatiquement. Lancez-le manuellement.
|
||||
exit /b 1
|
||||
|
||||
:: ============================================================
|
||||
:: DESINSTALLATION
|
||||
:: ============================================================
|
||||
:UNINSTALL
|
||||
cls
|
||||
echo ============================================================
|
||||
echo DESINSTALLATION de %APP_NAME%
|
||||
echo ============================================================
|
||||
echo.
|
||||
echo Seront supprimes :
|
||||
echo - Les scripts CDImp dans chaque dossier Acrobat\^<version^>\JavaScripts
|
||||
echo - Le plugin natif ImposingLicence.api ^(s'il a ete installe^)
|
||||
echo - %INSTALL_DIR% ^(code source local, cle de licence en registre conservee^)
|
||||
echo.
|
||||
set /p "CONFIRM=Confirmer ? [O/N] : "
|
||||
if /i "%CONFIRM%" neq "O" goto MENU
|
||||
|
||||
echo.
|
||||
if exist "%APPDATA%\Adobe\Acrobat" (
|
||||
for /d %%D in ("%APPDATA%\Adobe\Acrobat\*") do (
|
||||
del /q "%%D\JavaScripts\Imposition-*.js" 2>nul
|
||||
del /q "%%D\Plug_ins3\ImposingLicence.api" 2>nul
|
||||
)
|
||||
)
|
||||
echo [OK] Scripts et plugin supprimes
|
||||
|
||||
rmdir /s /q "%INSTALL_DIR%" 2>nul
|
||||
echo [OK] %INSTALL_DIR% supprime
|
||||
|
||||
echo.
|
||||
echo Pour retirer aussi la cle de licence enregistree :
|
||||
echo supprimez la cle de registre HKCU\Software\Copydev\ImposingAcrobat
|
||||
echo.
|
||||
echo ============================================================
|
||||
echo DESINSTALLATION TERMINEE
|
||||
echo ============================================================
|
||||
echo.
|
||||
pause
|
||||
goto MENU
|
||||
|
||||
:: ============================================================
|
||||
:FIN
|
||||
echo Au revoir !
|
||||
timeout /t 2 >nul
|
||||
exit /b 0
|
||||
225
acrobat-plugin/native/LicenceVerifier.cpp
Executable file
225
acrobat-plugin/native/LicenceVerifier.cpp
Executable file
@@ -0,0 +1,225 @@
|
||||
// LicenceVerifier.cpp
|
||||
// ---------------------------------------------------------------------------
|
||||
// Voir LicenceVerifier.h pour le contexte general.
|
||||
//
|
||||
// Le parsing JSON est volontairement minimal (recherche de sous-chaines) car
|
||||
// le SDK Acrobat ne fournit pas de bibliotheque JSON et on souhaite eviter
|
||||
// toute dependance externe pour un plugin aussi cible. Le format attendu de
|
||||
// license.php est celui deja documente pour le projet "impose" :
|
||||
// { "active": true/false, "offline_timeout_hours": 24, ... }
|
||||
// Si le serveur utilise plutot un champ "valid" au lieu de "active", les
|
||||
// deux sont acceptes. A AJUSTER si le format reel differe (voir TestConsole
|
||||
// pour verifier la reponse brute sans avoir a passer par Acrobat).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include "LicenceVerifier.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <wininet.h>
|
||||
#include <shlwapi.h>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
|
||||
#pragma comment(lib, "Wininet.lib")
|
||||
#pragma comment(lib, "Advapi32.lib")
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
namespace CDImpLicence {
|
||||
|
||||
static const wchar_t* CLE_REGISTRE = L"Software\\Copydev\\ImposingAcrobat";
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Utilitaires de parsing minimal (pas de dependance JSON externe)
|
||||
// -------------------------------------------------------------------
|
||||
static bool ContientChampBooleenVrai(const std::string& json, const char* champ) {
|
||||
std::string motif = std::string("\"") + champ + "\"";
|
||||
size_t pos = json.find(motif);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
pos = json.find(':', pos);
|
||||
if (pos == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
// Ignore les espaces apres ':'
|
||||
pos++;
|
||||
while (pos < json.size() && isspace((unsigned char)json[pos])) {
|
||||
pos++;
|
||||
}
|
||||
return json.compare(pos, 4, "true") == 0;
|
||||
}
|
||||
|
||||
static int LireChampEntier(const std::string& json, const char* champ, int defaut) {
|
||||
std::string motif = std::string("\"") + champ + "\"";
|
||||
size_t pos = json.find(motif);
|
||||
if (pos == std::string::npos) {
|
||||
return defaut;
|
||||
}
|
||||
pos = json.find(':', pos);
|
||||
if (pos == std::string::npos) {
|
||||
return defaut;
|
||||
}
|
||||
pos++;
|
||||
while (pos < json.size() && isspace((unsigned char)json[pos])) {
|
||||
pos++;
|
||||
}
|
||||
int valeur = atoi(json.c_str() + pos);
|
||||
return (valeur > 0) ? valeur : defaut;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Identifiants machine
|
||||
// -------------------------------------------------------------------
|
||||
std::wstring ObtenirHostname() {
|
||||
wchar_t nom[256] = { 0 };
|
||||
DWORD taille = 256;
|
||||
if (GetComputerNameW(nom, &taille)) {
|
||||
return std::wstring(nom);
|
||||
}
|
||||
return L"Inconnu";
|
||||
}
|
||||
|
||||
std::wstring ObtenirMachineId() {
|
||||
wchar_t nomVolume[MAX_PATH] = { 0 };
|
||||
DWORD numeroSerie = 0;
|
||||
// Volume serial number du lecteur systeme : stable pour une
|
||||
// installation Windows donnee, suffisant pour le comptage
|
||||
// d'appareils cote serveur (pas un UUID materiel, mais standard
|
||||
// Win32 fiable, sans dependance WMI/COM).
|
||||
wchar_t racineSysteme[4] = L"C:\\";
|
||||
GetWindowsDirectoryW(nomVolume, MAX_PATH);
|
||||
if (wcslen(nomVolume) >= 2) {
|
||||
racineSysteme[0] = nomVolume[0];
|
||||
}
|
||||
GetVolumeInformationW(racineSysteme, nullptr, 0, &numeroSerie, nullptr, nullptr, nullptr, 0);
|
||||
|
||||
wchar_t buffer[64];
|
||||
swprintf_s(buffer, 64, L"%08X-%s", numeroSerie, ObtenirHostname().c_str());
|
||||
return std::wstring(buffer);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Requete HTTP (WinINet)
|
||||
// -------------------------------------------------------------------
|
||||
static std::wstring EncoderURL(const std::wstring& valeur) {
|
||||
wchar_t tampon[1024];
|
||||
DWORD taille = 1024;
|
||||
if (UrlEscapeW(valeur.c_str(), tampon, &taille, URL_ESCAPE_PERCENT)) {
|
||||
return std::wstring(tampon);
|
||||
}
|
||||
return valeur;
|
||||
}
|
||||
|
||||
ResultatVerification VerifierLicence(
|
||||
const std::wstring& serveurUrl,
|
||||
const std::wstring& cleLicence,
|
||||
const std::wstring& machineId,
|
||||
const std::wstring& hostname,
|
||||
const std::wstring& produit
|
||||
) {
|
||||
ResultatVerification resultat;
|
||||
|
||||
std::wstring url = serveurUrl
|
||||
+ L"?key=" + EncoderURL(cleLicence)
|
||||
+ L"&machine_id=" + EncoderURL(machineId)
|
||||
+ L"&hostname=" + EncoderURL(hostname)
|
||||
+ L"&product=" + EncoderURL(produit);
|
||||
|
||||
HINTERNET hInternet = InternetOpenW(L"CopydevImposingAcrobat/1.0",
|
||||
INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0);
|
||||
if (!hInternet) {
|
||||
resultat.erreur = "InternetOpenW a echoue";
|
||||
return resultat;
|
||||
}
|
||||
|
||||
// Timeout raisonnable : ne pas bloquer le demarrage d'Acrobat
|
||||
// indefiniment si le serveur ne repond pas.
|
||||
DWORD timeoutMs = 5000;
|
||||
InternetSetOptionW(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
|
||||
InternetSetOptionW(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &timeoutMs, sizeof(timeoutMs));
|
||||
|
||||
HINTERNET hUrl = InternetOpenUrlW(hInternet, url.c_str(), nullptr, 0,
|
||||
INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE, 0);
|
||||
if (!hUrl) {
|
||||
resultat.erreur = "InternetOpenUrlW a echoue (reseau indisponible ou serveur inaccessible)";
|
||||
InternetCloseHandle(hInternet);
|
||||
return resultat;
|
||||
}
|
||||
|
||||
char tampon[2048];
|
||||
DWORD octetsLus = 0;
|
||||
std::string corps;
|
||||
while (InternetReadFile(hUrl, tampon, sizeof(tampon) - 1, &octetsLus) && octetsLus > 0) {
|
||||
tampon[octetsLus] = '\0';
|
||||
corps += tampon;
|
||||
}
|
||||
|
||||
InternetCloseHandle(hUrl);
|
||||
InternetCloseHandle(hInternet);
|
||||
|
||||
if (corps.empty()) {
|
||||
resultat.erreur = "Reponse vide du serveur de licence";
|
||||
return resultat;
|
||||
}
|
||||
|
||||
resultat.succesReseau = true;
|
||||
resultat.reponseBrute = corps;
|
||||
resultat.valide = ContientChampBooleenVrai(corps, "active") || ContientChampBooleenVrai(corps, "valid");
|
||||
resultat.offlineTimeoutHeures = LireChampEntier(corps, "offline_timeout_hours", 24);
|
||||
|
||||
return resultat;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Registre Windows
|
||||
// -------------------------------------------------------------------
|
||||
void EcrireVerdictRegistre(bool valide, int dureeToleranceHeures) {
|
||||
HKEY hCle;
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, CLE_REGISTRE, 0, nullptr,
|
||||
REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hCle, nullptr) != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
long long expiration = (long long)time(nullptr) + (long long)dureeToleranceHeures * 3600LL;
|
||||
|
||||
wchar_t valeurOK[2];
|
||||
swprintf_s(valeurOK, 2, L"%d", valide ? 1 : 0);
|
||||
wchar_t valeurExpiration[32];
|
||||
swprintf_s(valeurExpiration, 32, L"%lld", expiration);
|
||||
|
||||
RegSetValueExW(hCle, L"LicenceOK", 0, REG_SZ,
|
||||
(const BYTE*)valeurOK, (DWORD)((wcslen(valeurOK) + 1) * sizeof(wchar_t)));
|
||||
RegSetValueExW(hCle, L"LicenceValideJusqua", 0, REG_SZ,
|
||||
(const BYTE*)valeurExpiration, (DWORD)((wcslen(valeurExpiration) + 1) * sizeof(wchar_t)));
|
||||
|
||||
RegCloseKey(hCle);
|
||||
}
|
||||
|
||||
bool LireVerdictRegistre(bool& valideOut, long long& expirationUnixOut) {
|
||||
HKEY hCle;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, CLE_REGISTRE, 0, KEY_READ, &hCle) != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t valeurOK[16] = { 0 };
|
||||
DWORD tailleOK = sizeof(valeurOK);
|
||||
wchar_t valeurExpiration[32] = { 0 };
|
||||
DWORD tailleExpiration = sizeof(valeurExpiration);
|
||||
|
||||
bool ok1 = RegQueryValueExW(hCle, L"LicenceOK", nullptr, nullptr,
|
||||
(LPBYTE)valeurOK, &tailleOK) == ERROR_SUCCESS;
|
||||
bool ok2 = RegQueryValueExW(hCle, L"LicenceValideJusqua", nullptr, nullptr,
|
||||
(LPBYTE)valeurExpiration, &tailleExpiration) == ERROR_SUCCESS;
|
||||
|
||||
RegCloseKey(hCle);
|
||||
|
||||
if (!ok1 || !ok2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
valideOut = (_wtoi(valeurOK) == 1);
|
||||
expirationUnixOut = _wtoi64(valeurExpiration);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace CDImpLicence
|
||||
54
acrobat-plugin/native/LicenceVerifier.h
Executable file
54
acrobat-plugin/native/LicenceVerifier.h
Executable file
@@ -0,0 +1,54 @@
|
||||
// LicenceVerifier.h
|
||||
// ---------------------------------------------------------------------------
|
||||
// Verification de licence Vision (meme serveur/API que le projet "impose") -
|
||||
// implementation Win32 pure (WinINet + Registre), independante du SDK
|
||||
// Acrobat. Peut etre compilee et testee comme executable console autonome
|
||||
// via TestConsole.cpp avant d'etre integree au plugin Acrobat (PluginMain.cpp).
|
||||
//
|
||||
// Dependances : Wininet.lib (WinINet), Advapi32.lib (Registre) - standard
|
||||
// Win32, disponibles avec n'importe quelle installation de Visual Studio.
|
||||
// ---------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace CDImpLicence {
|
||||
|
||||
struct ResultatVerification {
|
||||
bool succesReseau = false; // la requete HTTP a reussi (reponse recue)
|
||||
bool valide = false; // la licence est active selon le serveur
|
||||
int offlineTimeoutHeures = 24;
|
||||
std::string erreur; // message d'erreur eventuel
|
||||
std::string reponseBrute; // corps de la reponse, pour diagnostic
|
||||
};
|
||||
|
||||
// Construit l'URL de verification et effectue la requete GET.
|
||||
// serveurUrl : ex. "https://vision.copydev.fr/api/license.php"
|
||||
ResultatVerification VerifierLicence(
|
||||
const std::wstring& serveurUrl,
|
||||
const std::wstring& cleLicence,
|
||||
const std::wstring& machineId,
|
||||
const std::wstring& hostname,
|
||||
const std::wstring& produit
|
||||
);
|
||||
|
||||
// Identifiant machine stable : tente d'utiliser le nom de la machine
|
||||
// Windows (GetComputerNameW) combine au volume serial number du disque
|
||||
// systeme (GetVolumeInformationW), deux API Win32 standard et fiables -
|
||||
// contrairement a l'approche JS qui devait generer un identifiant
|
||||
// aleatoire faute d'acces materiel direct.
|
||||
std::wstring ObtenirMachineId();
|
||||
std::wstring ObtenirHostname();
|
||||
|
||||
// Ecrit le verdict de licence dans HKCU\Software\Copydev\ImposingAcrobat
|
||||
// sous forme de chaines REG_SZ simples (lisibles depuis le JS via
|
||||
// WScript.Shell.RegRead, qui gere mal certains types REG_DWORD/QWORD) :
|
||||
// LicenceOK "1" ou "0"
|
||||
// LicenceValideJusqua timestamp Unix (secondes, en texte)
|
||||
void EcrireVerdictRegistre(bool valide, int dureeToleranceHeures);
|
||||
|
||||
// Relit le verdict actuellement stocke (utilise par TestConsole.cpp pour
|
||||
// verifier l'ecriture, et a titre de reference pour l'equivalent JS).
|
||||
bool LireVerdictRegistre(bool& valideOut, long long& expirationUnixOut);
|
||||
|
||||
} // namespace CDImpLicence
|
||||
109
acrobat-plugin/native/PluginMain.cpp
Executable file
109
acrobat-plugin/native/PluginMain.cpp
Executable file
@@ -0,0 +1,109 @@
|
||||
// PluginMain.cpp
|
||||
// ---------------------------------------------------------------------------
|
||||
// Squelette de plugin Acrobat (.api) dont l'unique role est d'appeler
|
||||
// CDImpLicence::VerifierLicence() au demarrage d'Acrobat et d'ecrire le
|
||||
// verdict dans le Registre (voir LicenceVerifier.h/.cpp). Ce fichier ne
|
||||
// touche a aucune fonctionnalite d'imposition : tout le reste de la suite
|
||||
// reste dans les Folder-Level Scripts JS deja en place
|
||||
// (/mnt/homeshare/Documents/Projet/imposing/src/), qui lisent ce verdict.
|
||||
//
|
||||
// ============================================================================
|
||||
// AVERTISSEMENT MAJEUR - A LIRE AVANT DE COMPILER
|
||||
// ============================================================================
|
||||
// Le code ci-dessous suit le squelette de plugin le plus communement
|
||||
// documente dans les exemples du Plug-in SDK Acrobat ("HelloWorld" et
|
||||
// derives), MAIS :
|
||||
// - cet environnement de developpement n'a ni le SDK Acrobat, ni Windows,
|
||||
// ni Visual Studio : ce fichier n'a PU ETRE NI COMPILE NI TESTE ;
|
||||
// - les macros/signatures exactes de handshake (PIHandshake, gExtensionID,
|
||||
// PIPlugInInit, l'enregistrement de l'export HFT) varient legerement
|
||||
// entre versions du SDK (et notamment entre les SDK 32 bits historiques
|
||||
// et les SDK modernes 64 bits) ;
|
||||
// - il FAUT remplacer ce squelette par le vrai boilerplate fourni dans le
|
||||
// dossier "Sample Plug-ins" du SDK que vous installez (generalement
|
||||
// PIMain.cpp dans chaque exemple), et n'y inserer que l'appel a
|
||||
// CDImpLicence::VerifierLicence() + EcrireVerdictRegistre() dans la
|
||||
// fonction d'initialisation du plugin.
|
||||
// La partie fiable et reutilisable telle quelle est LicenceVerifier.cpp/.h
|
||||
// (Win32 pur, deja validable independamment via TestConsole.cpp).
|
||||
// ============================================================================
|
||||
|
||||
#include "PIHeaders.h" // a fournir par le SDK Acrobat (non present ici)
|
||||
#include <windows.h>
|
||||
#include "LicenceVerifier.h"
|
||||
|
||||
// Identifiants a definir selon votre enregistrement developpeur Adobe
|
||||
// (Tools > JavaScript Debugger n'est pas concerne ici : c'est l'ID
|
||||
// d'extension attribue lors de l'inscription au programme Acrobat
|
||||
// Solutions/Integration Partner, requis pour distribuer un plugin signe).
|
||||
extern "C" const char* gExtensionID = "com.copydev.imposingacrobat.licence";
|
||||
|
||||
static const wchar_t* SERVEUR_LICENCE = L"https://vision.copydev.fr/api/license.php";
|
||||
static const wchar_t* PRODUIT = L"imposing-acrobat";
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Verification effectuee une fois, a l'initialisation du plugin (donc une
|
||||
// fois par session Acrobat). Suffisant pour la semantique de tolerance
|
||||
// hors-ligne deja en place cote serveur (offline_timeout_hours).
|
||||
// -----------------------------------------------------------------------
|
||||
static void EffectuerVerificationLicence() {
|
||||
// La cle de licence est lue depuis le Registre si deja saisie via le
|
||||
// dialogue JS "Gerer la licence..." (Imposition-00b-Licence.js stocke
|
||||
// global.cdImpLicenceCle via global.setPersistent, qui est in fine
|
||||
// persiste par Acrobat dans son propre stockage de preferences - PAS le
|
||||
// meme emplacement que celui utilise ici cote natif). Pour partager la
|
||||
// cle entre JS et natif de facon fiable, le plus simple est de la
|
||||
// stocker aussi dans le Registre depuis le JS (a ajouter dans
|
||||
// Imposition-00b-Licence.js : ecrire la cle saisie sous
|
||||
// HKCU\Software\Copydev\ImposingAcrobat\CleLicence via
|
||||
// WScript.Shell.RegWrite, en plus de global.setPersistent).
|
||||
wchar_t cleLicence[256] = { 0 };
|
||||
HKEY hCle;
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Copydev\\ImposingAcrobat",
|
||||
0, KEY_READ, &hCle) == ERROR_SUCCESS) {
|
||||
DWORD taille = sizeof(cleLicence);
|
||||
RegQueryValueExW(hCle, L"CleLicence", nullptr, nullptr, (LPBYTE)cleLicence, &taille);
|
||||
RegCloseKey(hCle);
|
||||
}
|
||||
|
||||
if (wcslen(cleLicence) == 0) {
|
||||
// Aucune cle connue cote natif : on n'ecrit aucun verdict, le JS
|
||||
// retombera sur sa propre verification (voir Imposition-00b-Licence.js).
|
||||
return;
|
||||
}
|
||||
|
||||
std::wstring machineId = CDImpLicence::ObtenirMachineId();
|
||||
std::wstring hostname = CDImpLicence::ObtenirHostname();
|
||||
|
||||
CDImpLicence::ResultatVerification resultat = CDImpLicence::VerifierLicence(
|
||||
SERVEUR_LICENCE, cleLicence, machineId, hostname, PRODUIT);
|
||||
|
||||
if (resultat.succesReseau) {
|
||||
CDImpLicence::EcrireVerdictRegistre(resultat.valide, resultat.offlineTimeoutHeures);
|
||||
}
|
||||
// Si la requete reseau echoue, on n'ecrit rien : le verdict precedent
|
||||
// (s'il existe, avec son timestamp d'expiration) reste en place et sera
|
||||
// evalue tel quel par le JS (logique de tolerance hors-ligne).
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree d'initialisation du plugin. Le nom exact et la signature
|
||||
// de cette fonction DOIVENT etre repris du boilerplate PIMain.cpp de votre
|
||||
// SDK (le nom "PluginInit" ci-dessous est indicatif).
|
||||
// -----------------------------------------------------------------------
|
||||
ACCB1 ASBool ACCB2 PluginInit(void) {
|
||||
EffectuerVerificationLicence();
|
||||
return true; // true = le plugin s'est initialise correctement
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Handshake / export table : A REMPLACER INTEGRALEMENT par le contenu du
|
||||
// boilerplate de votre version du SDK (PIMain.cpp, PIRequir.h, etc.). Conserve
|
||||
// ici uniquement comme rappel de la structure generale attendue.
|
||||
// -----------------------------------------------------------------------
|
||||
/*
|
||||
ACCB1 ASBool ACCB2 PIHandshake(...) {
|
||||
// ... initialisation standard du SDK ...
|
||||
return PluginInit();
|
||||
}
|
||||
*/
|
||||
82
acrobat-plugin/native/TestConsole.cpp
Executable file
82
acrobat-plugin/native/TestConsole.cpp
Executable file
@@ -0,0 +1,82 @@
|
||||
// TestConsole.cpp
|
||||
// ---------------------------------------------------------------------------
|
||||
// Executable console autonome pour valider LicenceVerifier.cpp SANS le SDK
|
||||
// Acrobat (pas besoin d'Acrobat installe ni du Plug-in SDK pour ce test).
|
||||
//
|
||||
// Build rapide (Visual Studio Developer Command Prompt) :
|
||||
// cl /EHsc /std:c++14 TestConsole.cpp LicenceVerifier.cpp ^
|
||||
// wininet.lib advapi32.lib shlwapi.lib
|
||||
//
|
||||
// Ou : creer un projet "Application console" Visual Studio classique avec
|
||||
// ces deux fichiers .cpp + LicenceVerifier.h.
|
||||
//
|
||||
// A FAIRE AVANT D'INTEGRER AU PLUGIN ACROBAT :
|
||||
// 1. Lancer ce programme avec une cle de licence de test valide
|
||||
// (ex: COPYDEV-IMPOS-TEST-2026, comme pour le projet impose) et
|
||||
// verifier que la reponse brute du serveur correspond au parsing
|
||||
// attendu (champ "active" ou "valid", "offline_timeout_hours").
|
||||
// 2. Si le parsing echoue, ajuster ContientChampBooleenVrai/LireChampEntier
|
||||
// dans LicenceVerifier.cpp selon le format reel observe.
|
||||
// 3. Verifier que le Registre est bien ecrit (HKCU\Software\Copydev\
|
||||
// ImposingAcrobat) avec regedit, ou en relancant ce programme avec
|
||||
// l'option "lire" (voir ci-dessous).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include "LicenceVerifier.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
// Conversion simple (les reponses JSON attendues sont en ASCII).
|
||||
static std::wstring VersWstring(const std::string& s) {
|
||||
return std::wstring(s.begin(), s.end());
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[]) {
|
||||
if (argc >= 2 && std::wstring(argv[1]) == L"lire") {
|
||||
bool valide = false;
|
||||
long long expiration = 0;
|
||||
if (CDImpLicence::LireVerdictRegistre(valide, expiration)) {
|
||||
wprintf(L"Verdict en registre : valide=%d, expire le (unix)=%lld\n", valide ? 1 : 0, expiration);
|
||||
} else {
|
||||
wprintf(L"Aucun verdict trouve dans le registre.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
wprintf(L"Usage: TestConsole.exe <cle_licence> [serveur_url]\n");
|
||||
wprintf(L" TestConsole.exe lire (relit le verdict deja ecrit en registre)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::wstring cle = argv[1];
|
||||
std::wstring serveur = (argc >= 3) ? argv[2] : L"https://vision.copydev.fr/api/license.php";
|
||||
std::wstring produit = L"imposing-acrobat";
|
||||
|
||||
std::wstring machineId = CDImpLicence::ObtenirMachineId();
|
||||
std::wstring hostname = CDImpLicence::ObtenirHostname();
|
||||
|
||||
wprintf(L"Machine ID : %s\n", machineId.c_str());
|
||||
wprintf(L"Hostname : %s\n", hostname.c_str());
|
||||
wprintf(L"Serveur : %s\n", serveur.c_str());
|
||||
wprintf(L"Produit : %s\n\n", produit.c_str());
|
||||
|
||||
CDImpLicence::ResultatVerification resultat = CDImpLicence::VerifierLicence(
|
||||
serveur, cle, machineId, hostname, produit);
|
||||
|
||||
wprintf(L"Succes reseau : %d\n", resultat.succesReseau ? 1 : 0);
|
||||
wprintf(L"Licence valide : %d\n", resultat.valide ? 1 : 0);
|
||||
wprintf(L"Tolerance hors-ligne: %d heures\n", resultat.offlineTimeoutHeures);
|
||||
if (!resultat.erreur.empty()) {
|
||||
wprintf(L"Erreur : %s\n", VersWstring(resultat.erreur).c_str());
|
||||
}
|
||||
wprintf(L"Reponse brute : %s\n\n", VersWstring(resultat.reponseBrute).c_str());
|
||||
|
||||
if (resultat.succesReseau) {
|
||||
CDImpLicence::EcrireVerdictRegistre(resultat.valide, resultat.offlineTimeoutHeures);
|
||||
wprintf(L"Verdict ecrit dans HKCU\\Software\\Copydev\\ImposingAcrobat.\n");
|
||||
wprintf(L"Relancez avec l'argument \"lire\" pour le verifier.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
231
acrobat-plugin/src/Imposition-00-Core.js
Executable file
231
acrobat-plugin/src/Imposition-00-Core.js
Executable file
@@ -0,0 +1,231 @@
|
||||
// Imposition-00-Core.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 0 : Noyau (namespace, utilitaires, menu racine)
|
||||
//
|
||||
// Ce fichier doit etre charge en premier (prefixe "00") car il definit le
|
||||
// namespace global CDImp (Copydev Imposition) utilise par tous les autres
|
||||
// modules. Acrobat charge les scripts du dossier JavaScripts par ordre
|
||||
// alphabetique, donc le prefixe numerique garantit l'ordre d'initialisation.
|
||||
//
|
||||
// Emplacement attendu sous Windows :
|
||||
// %APPDATA%\Adobe\Acrobat\<version>\JavaScripts\ (utilisateur courant)
|
||||
// ou <InstallDir>\Acrobat\Javascripts\ (tous les utilisateurs)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Namespace global partage par tous les modules. "var" au niveau racine d'un
|
||||
// folder-level script devient une variable globale persistante pour la
|
||||
// session Acrobat (et non une variable "global" partagee entre documents,
|
||||
// qui necessiterait l'objet `global`).
|
||||
if (typeof CDImp === "undefined") {
|
||||
var CDImp = {};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Constantes
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.PT_PAR_MM = 72 / 25.4; // 1 mm en points PDF (~2.8346456693)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Utilitaires generaux
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Util = {
|
||||
|
||||
/**
|
||||
* Convertit des millimetres en points PDF.
|
||||
*/
|
||||
mmToPt: function (mm) {
|
||||
return mm * CDImp.PT_PAR_MM;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convertit des points PDF en millimetres.
|
||||
*/
|
||||
ptToMm: function (pt) {
|
||||
return pt / CDImp.PT_PAR_MM;
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute une fonction avec les privileges eleves necessaires aux
|
||||
* operations sur les fichiers / documents (creation, sauvegarde,
|
||||
* fermeture, ajout de menus...). Restaure toujours les privileges
|
||||
* standards via app.endPriv(), meme en cas d'erreur.
|
||||
*
|
||||
* @param {Function} fn fonction a executer en contexte privilegie
|
||||
* @returns la valeur retournee par fn, ou undefined en cas d'erreur
|
||||
*/
|
||||
avecPrivileges: function (fn) {
|
||||
var resultat;
|
||||
try {
|
||||
app.beginPriv();
|
||||
resultat = fn();
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur privilegiee : " + e.toString());
|
||||
} finally {
|
||||
app.endPriv();
|
||||
}
|
||||
return resultat;
|
||||
},
|
||||
|
||||
/**
|
||||
* Affiche une boite d'alerte d'erreur standardisee.
|
||||
*/
|
||||
erreur: function (message) {
|
||||
app.alert({
|
||||
cMsg: message,
|
||||
nIcon: 0, // erreur
|
||||
nType: 0 // OK
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Affiche une boite d'information standardisee.
|
||||
*/
|
||||
info: function (message) {
|
||||
app.alert({
|
||||
cMsg: message,
|
||||
nIcon: 3, // information
|
||||
nType: 0 // OK
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Retourne le document actif passe en parametre, ou a defaut le premier
|
||||
* document ouvert dans Acrobat. Leve une erreur explicite si aucun
|
||||
* document n'est ouvert.
|
||||
*/
|
||||
getDocActif: function (docPotentiel) {
|
||||
var doc = docPotentiel;
|
||||
if (!doc) {
|
||||
if (app.activeDocs && app.activeDocs.length > 0) {
|
||||
doc = app.activeDocs[0];
|
||||
}
|
||||
}
|
||||
if (!doc) {
|
||||
throw new Error("Aucun document PDF ouvert.");
|
||||
}
|
||||
return doc;
|
||||
},
|
||||
|
||||
/**
|
||||
* Demande un nombre a l'utilisateur via app.response, avec valeur par
|
||||
* defaut et validation. Retourne null si l'utilisateur annule.
|
||||
*/
|
||||
demanderNombre: function (question, titre, defaut) {
|
||||
var saisie = app.response({ cQuestion: question, cTitle: titre || "Imposition Professionnelle", cDefault: String(defaut) });
|
||||
if (saisie === null) {
|
||||
return null;
|
||||
}
|
||||
var n = parseFloat(saisie);
|
||||
return isNaN(n) ? defaut : n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Place le contenu integral de la page source nSrcPage (1-based) du
|
||||
* document srcDoc a l'interieur du rectangle rectDest (en points PDF,
|
||||
* [llx, lly, urx, ury]) de la page nDestPage (0-based) du document
|
||||
* destDoc, avec mise a l'echelle automatique si rectDest a une taille
|
||||
* differente de la page source.
|
||||
*
|
||||
* Technique : on cree un template a partir de la page source, on force
|
||||
* temporairement la CropBox de la page de destination a rectDest (ce qui
|
||||
* determine la zone et donc l'echelle d'affichage du contenu "spawn"),
|
||||
* on spawn le template, puis on restaure la CropBox d'origine de la
|
||||
* page de destination. C'est la technique standard utilisee en
|
||||
* JavaScript pur pour Acrobat (sans plugin natif) ; a valider dans une
|
||||
* vraie session Acrobat Pro (voir notes dans chaque module appelant).
|
||||
*
|
||||
* @param {Doc} srcDoc
|
||||
* @param {Number|null} nSrcPage numero 1-based, ou null/0 pour ne rien placer
|
||||
* @param {Doc} destDoc
|
||||
* @param {Number} nDestPage index 0-based
|
||||
* @param {Array} rectDest [llx, lly, urx, ury] en points
|
||||
*/
|
||||
placerPageDansRect: function (srcDoc, nSrcPage, destDoc, nDestPage, rectDest) {
|
||||
if (!nSrcPage) {
|
||||
return;
|
||||
}
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
var nomTpl = "CDImp_tpl_" + nSrcPage + "_" + nDestPage + "_" + (new Date()).getTime();
|
||||
var tpl = srcDoc.createTemplate({ cName: nomTpl, nPage: nSrcPage - 1 });
|
||||
var cropOrigineDest = destDoc.getPageBox({ nPage: nDestPage, cBox: "Crop" });
|
||||
try {
|
||||
destDoc.setPageBoxes({ nPage: nDestPage, cBox: "Crop", rBox: rectDest });
|
||||
tpl.spawn({ cDocName: destDoc, nPage: nDestPage, bRename: false, bOverlay: true });
|
||||
} finally {
|
||||
destDoc.setPageBoxes({ nPage: nDestPage, cBox: "Crop", rBox: cropOrigineDest });
|
||||
tpl.remove();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Extrait une sous-region rectSource (en points PDF, [llx, lly, urx, ury]
|
||||
* dans le repere de la page source) de la page nSrcPage (1-based) de
|
||||
* srcDoc, et la place a l'echelle 1:1 sur la page nDestPage (0-based) de
|
||||
* destDoc (qui doit deja avoir la taille de rectSource).
|
||||
*
|
||||
* Technique symetrique de placerPageDansRect : ici on recadre
|
||||
* temporairement la CropBox de la page SOURCE (pour n'exposer que la
|
||||
* region voulue), on cree le template, on restaure la CropBox source,
|
||||
* puis on spawn sur la page de destination. Utilise pour le decoupage
|
||||
* de pages (Module 4) et la delivretisation (Module 2).
|
||||
*
|
||||
* @param {Doc} srcDoc
|
||||
* @param {Number} nSrcPage numero 1-based
|
||||
* @param {Array} rectSource [llx, lly, urx, ury] dans le repere de la page source
|
||||
* @param {Doc} destDoc
|
||||
* @param {Number} nDestPage index 0-based
|
||||
*/
|
||||
extraireRegionPage: function (srcDoc, nSrcPage, rectSource, destDoc, nDestPage) {
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
var cropOrigineSrc = srcDoc.getPageBox({ nPage: nSrcPage - 1, cBox: "Crop" });
|
||||
try {
|
||||
srcDoc.setPageBoxes({ nPage: nSrcPage - 1, cBox: "Crop", rBox: rectSource });
|
||||
var nomTpl = "CDImp_ext_" + nSrcPage + "_" + nDestPage + "_" + (new Date()).getTime();
|
||||
var tpl = srcDoc.createTemplate({ cName: nomTpl, nPage: nSrcPage - 1 });
|
||||
try {
|
||||
tpl.spawn({ cDocName: destDoc, nPage: nDestPage, bRename: false, bOverlay: true });
|
||||
} finally {
|
||||
tpl.remove();
|
||||
}
|
||||
} finally {
|
||||
srcDoc.setPageBoxes({ nPage: nSrcPage - 1, cBox: "Crop", rBox: cropOrigineSrc });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Formats de feuille standards (largeur x hauteur, en mm, portrait)
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Util.FORMATS_MM = {
|
||||
A3: [297, 420],
|
||||
A4: [210, 297],
|
||||
A5: [148, 210],
|
||||
SRA3: [320, 450],
|
||||
SRA4: [225, 320],
|
||||
LETTER: [215.9, 279.4]
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Menu racine "Imposition Pro"
|
||||
// -----------------------------------------------------------------------
|
||||
// Cree un menu de premier niveau avec un seul point d'entree qui ouvre le
|
||||
// panneau de controle principal (boite de dialogue maitresse, voir Module 1).
|
||||
// La creation/modification de menus est une operation privilegiee.
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
try {
|
||||
app.addMenuItem({
|
||||
cName: "CDImpRacine",
|
||||
cParent: "Edit", // accroche dans le menu Edition (peut etre adapte)
|
||||
cExec: "CDImp.UI.ouvrirPanneauPrincipal(this);",
|
||||
cEnable: "event.rc = (CDImp.UI != undefined);",
|
||||
nPos: -1
|
||||
});
|
||||
} catch (e) {
|
||||
// Si le menu existe deja (rechargement de script), on ignore
|
||||
// silencieusement l'erreur de doublon.
|
||||
}
|
||||
});
|
||||
342
acrobat-plugin/src/Imposition-00b-Licence.js
Executable file
342
acrobat-plugin/src/Imposition-00b-Licence.js
Executable file
@@ -0,0 +1,342 @@
|
||||
// Imposition-00b-Licence.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 0b : Verification de licence (serveur Vision)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant). Doit etre charge
|
||||
// AVANT Imposition-01-UI.js (le prefixe "00b" garantit cet ordre).
|
||||
//
|
||||
// Reutilise le serveur de licence Vision deja en place pour le projet
|
||||
// "Copydev Imposing Tool" (impose) : meme API license.php, meme logique de
|
||||
// cache hors-ligne avec duree de tolerance, meme principe de plafond
|
||||
// d'appareils (max_devices) gere cote serveur. Seul le champ "product"
|
||||
// change pour distinguer ce plugin Acrobat des autres produits Copydev.
|
||||
//
|
||||
// AVERTISSEMENTS TECHNIQUES - a tester dans Acrobat Pro reel :
|
||||
// - Net.HTTP.request() est l'API documentee pour les requetes HTTP depuis
|
||||
// un script Acrobat privilegie, mais sa disponibilite depend des
|
||||
// reglages de securite reseau d'Acrobat (Preferences > Securite
|
||||
// (avancee) > Gestionnaire de confiance > acces internet pour les
|
||||
// scripts non-PDF). A activer/whitelister si necessaire.
|
||||
// - La lecture du flux de reponse (Stream.read()) est implementee selon le
|
||||
// schema le plus communement documente, mais n'a pas pu etre executee
|
||||
// dans cet environnement de developpement (pas d'Acrobat installe) :
|
||||
// ajuster _lireFluxReponse() si le parsing JSON echoue en conditions
|
||||
// reelles.
|
||||
// - L'identifiant machine (machine_id) repose sur ActiveXObject (COM),
|
||||
// disponible uniquement sous Windows pour des scripts de dossier
|
||||
// (folder-level) de confiance. En cas d'indisponibilite, on retombe sur
|
||||
// un identifiant genere une fois et persiste localement (moins robuste
|
||||
// contre la copie de licence, mais fonctionnel).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-00b-Licence.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Licence = CDImp.Licence || {};
|
||||
|
||||
CDImp.Licence.CONFIG = {
|
||||
serveurUrl: "https://vision.copydev.fr/api/license.php",
|
||||
produit: "imposing-acrobat",
|
||||
dureeCacheHeuresParDefaut: 24 // utilisee si le serveur ne renvoie pas offline_timeout_hours
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Identifiants machine
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Nom de la machine, via WSH (Windows uniquement, scripts de dossier
|
||||
* privilegies). Retombe sur "Inconnu" si indisponible.
|
||||
*/
|
||||
CDImp.Licence._obtenirHostname = function () {
|
||||
try {
|
||||
var reseau = new ActiveXObject("WScript.Network");
|
||||
return String(reseau.ComputerName);
|
||||
} catch (e) {
|
||||
return "Inconnu";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Identifiant machine stable, persiste dans les preferences globales
|
||||
* d'Acrobat (genere une seule fois). Pas un identifiant materiel (UUID
|
||||
* BIOS), mais suffisant pour le comptage d'appareils cote serveur.
|
||||
*/
|
||||
CDImp.Licence._obtenirMachineId = function () {
|
||||
if (typeof global.cdImpMachineId !== "undefined" && global.cdImpMachineId) {
|
||||
return global.cdImpMachineId;
|
||||
}
|
||||
var id = "";
|
||||
for (var i = 0; i < 32; i++) {
|
||||
id += Math.floor(Math.random() * 16).toString(16);
|
||||
}
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
global.cdImpMachineId = id;
|
||||
global.setPersistent("cdImpMachineId", true);
|
||||
});
|
||||
return id;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Requete HTTP synchrone vers le serveur de licence
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Convertit le flux de reponse Net.HTTP en chaine de caracteres.
|
||||
*/
|
||||
CDImp.Licence._lireFluxReponse = function (msgStream) {
|
||||
try {
|
||||
var nTaille = msgStream.length;
|
||||
var aOctets = msgStream.read(nTaille);
|
||||
var texte = "";
|
||||
for (var i = 0; i < aOctets.length; i++) {
|
||||
texte += String.fromCharCode(aOctets[i]);
|
||||
}
|
||||
return texte;
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Effectue une requete GET synchrone et retourne { erreur, texte }.
|
||||
*/
|
||||
CDImp.Licence._requeteHTTPSync = function (url) {
|
||||
var resultat = { erreur: null, texte: null };
|
||||
try {
|
||||
Net.HTTP.request({
|
||||
cVerb: "GET",
|
||||
cURL: url,
|
||||
oHandler: {
|
||||
response: function (msgStream, status) {
|
||||
if (status && status >= 400) {
|
||||
resultat.erreur = "HTTP " + status;
|
||||
} else {
|
||||
resultat.texte = CDImp.Licence._lireFluxReponse(msgStream);
|
||||
}
|
||||
},
|
||||
error: function (msg, err) {
|
||||
resultat.erreur = (err || msg || "Erreur reseau inconnue").toString();
|
||||
}
|
||||
},
|
||||
bAsync: false
|
||||
});
|
||||
} catch (e) {
|
||||
resultat.erreur = e.toString();
|
||||
}
|
||||
return resultat;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Saisie / stockage de la cle de licence
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Licence._demanderCle = function () {
|
||||
var cle = app.response({
|
||||
cQuestion: "Cle de licence Copydev Imposing (Acrobat) :",
|
||||
cTitle: "Activation de la licence",
|
||||
cDefault: ""
|
||||
});
|
||||
return (cle && cle.length > 0) ? cle : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recopie la cle dans le Registre Windows (HKCU\Software\Copydev\
|
||||
* ImposingAcrobat\CleLicence), seul emplacement que le plugin natif
|
||||
* (voir /native/PluginMain.cpp) sait lire : global.setPersistent() stocke
|
||||
* la valeur dans le mecanisme de preferences interne d'Acrobat, pas dans
|
||||
* le Registre, donc cette ecriture explicite est necessaire pour que le
|
||||
* plugin natif et le JS partagent la meme cle. Echec silencieux si
|
||||
* ActiveXObject est indisponible (plugin natif alors simplement inutilisable,
|
||||
* le JS continue de fonctionner seul).
|
||||
*/
|
||||
CDImp.Licence._ecrireCleRegistre = function (cle) {
|
||||
try {
|
||||
var shell = new ActiveXObject("WScript.Shell");
|
||||
shell.RegWrite("HKCU\\Software\\Copydev\\ImposingAcrobat\\CleLicence", cle, "REG_SZ");
|
||||
} catch (e) {
|
||||
// pas grave : le plugin natif (s'il est installe) ne pourra pas
|
||||
// verifier la licence de son cote, le JS reste fonctionnel seul.
|
||||
}
|
||||
};
|
||||
|
||||
CDImp.Licence._obtenirCle = function () {
|
||||
if (typeof global.cdImpLicenceCle !== "undefined" && global.cdImpLicenceCle) {
|
||||
return global.cdImpLicenceCle;
|
||||
}
|
||||
var cle = CDImp.Licence._demanderCle();
|
||||
if (!cle) {
|
||||
return null;
|
||||
}
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
global.cdImpLicenceCle = cle;
|
||||
global.setPersistent("cdImpLicenceCle", true);
|
||||
});
|
||||
CDImp.Licence._ecrireCleRegistre(cle);
|
||||
return cle;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Verdict du plugin natif (voir /native/), lu en priorite s'il est present
|
||||
// et frais. Permet de s'appuyer sur une verification effectuee en code
|
||||
// compile (plus dur a lire/patcher qu'un .js) plutot que sur le seul check
|
||||
// JS ci-dessous. Si le plugin natif n'est pas installe ou n'a pas encore
|
||||
// ecrit de verdict, on retombe naturellement sur la verification JS pure
|
||||
// (aucune regression).
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Licence._lireVerdictNatif = function () {
|
||||
try {
|
||||
var shell = new ActiveXObject("WScript.Shell");
|
||||
var ok = shell.RegRead("HKCU\\Software\\Copydev\\ImposingAcrobat\\LicenceOK");
|
||||
var expirationStr = shell.RegRead("HKCU\\Software\\Copydev\\ImposingAcrobat\\LicenceValideJusqua");
|
||||
var expiration = parseInt(expirationStr, 10);
|
||||
var maintenant = Math.floor((new Date()).getTime() / 1000);
|
||||
|
||||
if (String(ok) === "1" && expiration > maintenant) {
|
||||
return { valide: true, source: "plugin_natif" };
|
||||
}
|
||||
return { valide: false, source: "plugin_natif", raison: "Verdict du plugin natif absent ou expire." };
|
||||
} catch (e) {
|
||||
return null; // plugin natif non installe / registre absent : pas d'info
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Verification (serveur, avec repli sur cache hors-ligne)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Verifie la licence auprès du serveur Vision. En cas d'echec reseau,
|
||||
* retombe sur le dernier resultat valide mis en cache, dans la limite de la
|
||||
* duree de tolerance hors-ligne (offline_timeout_hours renvoye par le
|
||||
* serveur, ou valeur par defaut).
|
||||
*
|
||||
* @returns {Object} { valide, source: "serveur"|"cache", donnees, raison }
|
||||
*/
|
||||
CDImp.Licence.verifier = function () {
|
||||
var verdictNatif = CDImp.Licence._lireVerdictNatif();
|
||||
if (verdictNatif && verdictNatif.valide) {
|
||||
return verdictNatif;
|
||||
}
|
||||
// Verdict natif absent, expire ou plugin non installe : on continue
|
||||
// avec la verification JS habituelle (HTTP + cache hors-ligne).
|
||||
|
||||
var cle = CDImp.Licence._obtenirCle();
|
||||
if (!cle) {
|
||||
return { valide: false, raison: "Aucune cle de licence saisie." };
|
||||
}
|
||||
|
||||
var machineId = CDImp.Licence._obtenirMachineId();
|
||||
var hostname = CDImp.Licence._obtenirHostname();
|
||||
var url = CDImp.Licence.CONFIG.serveurUrl
|
||||
+ "?key=" + encodeURIComponent(cle)
|
||||
+ "&machine_id=" + encodeURIComponent(machineId)
|
||||
+ "&hostname=" + encodeURIComponent(hostname)
|
||||
+ "&product=" + encodeURIComponent(CDImp.Licence.CONFIG.produit);
|
||||
|
||||
var reponse = CDImp.Licence._requeteHTTPSync(url);
|
||||
|
||||
if (reponse.erreur || !reponse.texte) {
|
||||
return CDImp.Licence._verifierCache(reponse.erreur);
|
||||
}
|
||||
|
||||
var data;
|
||||
try {
|
||||
data = JSON.parse(reponse.texte);
|
||||
} catch (e) {
|
||||
return CDImp.Licence._verifierCache("Reponse serveur illisible.");
|
||||
}
|
||||
|
||||
var valide = !!(data.active || data.valid);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
global.cdImpLicenceCache = { valide: valide, donnees: data, dateVerif: (new Date()).getTime() };
|
||||
global.setPersistent("cdImpLicenceCache", true);
|
||||
});
|
||||
|
||||
return { valide: valide, donnees: data, source: "serveur" };
|
||||
};
|
||||
|
||||
CDImp.Licence._verifierCache = function (raisonReseau) {
|
||||
var cache = global.cdImpLicenceCache;
|
||||
if (!cache) {
|
||||
return { valide: false, raison: "Serveur de licence inaccessible (" + (raisonReseau || "?") + ") et aucun cache local." };
|
||||
}
|
||||
var heuresEcoulees = ((new Date()).getTime() - cache.dateVerif) / 3600000;
|
||||
var tolerance = (cache.donnees && cache.donnees.offline_timeout_hours) || CDImp.Licence.CONFIG.dureeCacheHeuresParDefaut;
|
||||
|
||||
if (cache.valide && heuresEcoulees <= tolerance) {
|
||||
return { valide: true, donnees: cache.donnees, source: "cache", heuresEcoulees: heuresEcoulees };
|
||||
}
|
||||
return {
|
||||
valide: false,
|
||||
raison: "Serveur de licence inaccessible (" + (raisonReseau || "?") + ") et cache hors-ligne expire ou invalide\n(hors-ligne depuis ~" + Math.round(heuresEcoulees) + "h, tolerance " + tolerance + "h)."
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifie la licence et affiche une alerte bloquante si elle est invalide.
|
||||
* A appeler avant toute action des modules d'imposition.
|
||||
*
|
||||
* @returns {Boolean} true si l'utilisation peut continuer
|
||||
*/
|
||||
CDImp.Licence.verifierEtBloquerSiInvalide = function () {
|
||||
var resultat;
|
||||
try {
|
||||
resultat = CDImp.Licence.verifier();
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de la verification de la licence : " + e.toString());
|
||||
return false;
|
||||
}
|
||||
if (!resultat.valide) {
|
||||
CDImp.Util.erreur("Licence invalide ou expiree :\n" + (resultat.raison || "")
|
||||
+ "\n\nLa suite d'imposition professionnelle est desactivee.\nUtilisez \"Imposition Pro > Gerer la licence...\" pour saisir une cle valide.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Boite de dialogue simple permettant de saisir/remplacer la cle de licence
|
||||
* et de relancer immediatement une verification.
|
||||
*/
|
||||
CDImp.Licence.gererCle = function () {
|
||||
var cleActuelle = global.cdImpLicenceCle || "";
|
||||
var nouvelleCle = app.response({
|
||||
cQuestion: "Cle de licence Copydev Imposing (Acrobat) :",
|
||||
cTitle: "Gerer la licence",
|
||||
cDefault: cleActuelle
|
||||
});
|
||||
if (nouvelleCle === null || nouvelleCle === cleActuelle) {
|
||||
return;
|
||||
}
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
global.cdImpLicenceCle = nouvelleCle;
|
||||
global.setPersistent("cdImpLicenceCle", true);
|
||||
global.cdImpLicenceCache = null; // force une nouvelle verification serveur
|
||||
global.setPersistent("cdImpLicenceCache", true);
|
||||
});
|
||||
CDImp.Licence._ecrireCleRegistre(nouvelleCle);
|
||||
CDImp.Util.info("Cle enregistree. Redemarrez Acrobat pour que le plugin natif\n(s'il est installe) la prenne en compte au prochain demarrage.");
|
||||
var resultat = CDImp.Licence.verifier();
|
||||
if (resultat.valide) {
|
||||
CDImp.Util.info("Licence valide. Source : " + resultat.source + ".");
|
||||
} else {
|
||||
CDImp.Util.erreur("Licence invalide : " + (resultat.raison || ""));
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Entree de menu "Gerer la licence..."
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
try {
|
||||
app.addMenuItem({
|
||||
cName: "CDImpGererLicence",
|
||||
cParent: "Edit",
|
||||
cExec: "CDImp.Licence.gererCle();",
|
||||
cEnable: "event.rc = (CDImp.Licence != undefined);",
|
||||
nPos: -1
|
||||
});
|
||||
} catch (e) {
|
||||
// menu deja present (rechargement de script) : ignore
|
||||
}
|
||||
});
|
||||
154
acrobat-plugin/src/Imposition-01-UI.js
Executable file
154
acrobat-plugin/src/Imposition-01-UI.js
Executable file
@@ -0,0 +1,154 @@
|
||||
// Imposition-01-UI.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 1 : Panneau de controle principal (UI Dialog)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// IMPORTANT : le format de description utilise par app.execDialog() est tres
|
||||
// specifique et difficile a valider hors d'une session Acrobat reelle (cet
|
||||
// environnement de developpement n'a pas Acrobat installe). La structure
|
||||
// ci-dessous suit la convention documentee dans l'Annexe "Creating Dialogs"
|
||||
// du Acrobat DC SDK JavaScript Reference. A tester et ajuster dans Acrobat
|
||||
// Pro (les noms de "type" et d'evenements sont les points les plus fragiles).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-01-UI.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.UI = CDImp.UI || {};
|
||||
|
||||
// Codes de retour utilises pour savoir quel bouton a ete actionne dans le
|
||||
// panneau principal.
|
||||
CDImp.UI.ACTIONS = {
|
||||
LIVRET: 1,
|
||||
NUP: 2,
|
||||
DECOUPE: 3,
|
||||
MARGES: 4,
|
||||
REPERES: 5,
|
||||
AUTO: 6
|
||||
};
|
||||
|
||||
/**
|
||||
* Construit l'objet de description du panneau principal pour app.execDialog.
|
||||
* Les boutons referencent chacun un item_id ; le clic ferme le dialogue en
|
||||
* renvoyant le code d'action correspondant via dialog.end().
|
||||
*/
|
||||
CDImp.UI._construireDialoguePrincipal = function () {
|
||||
var A = CDImp.UI.ACTIONS;
|
||||
|
||||
return {
|
||||
description: {
|
||||
name: "Imposition Professionnelle",
|
||||
elements: [
|
||||
{
|
||||
type: "view",
|
||||
name: "Imposition Professionnelle",
|
||||
elements: [
|
||||
{
|
||||
type: "panel",
|
||||
align_children: "align_top",
|
||||
elements: [
|
||||
{ type: "static_text", name: "Choisissez un module d'imposition :" },
|
||||
{
|
||||
type: "view",
|
||||
align_children: "align_row",
|
||||
elements: [
|
||||
{
|
||||
type: "view",
|
||||
align_children: "align_column",
|
||||
elements: [
|
||||
{ type: "button", item_id: "btnLivret", name: "1. Creer un livret" },
|
||||
{ type: "button", item_id: "btnNUp", name: "2. N-Up / Step & Repeat" },
|
||||
{ type: "button", item_id: "btnDecoupe", name: "3. Decoupe & reassemblage" }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "view",
|
||||
align_children: "align_column",
|
||||
elements: [
|
||||
{ type: "button", item_id: "btnMarges", name: "4. Marges & cadrages" },
|
||||
{ type: "button", item_id: "btnReperes", name: "5. Reperes, textes, numerotation" },
|
||||
{ type: "button", item_id: "btnAuto", name: "6. Automatisation" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: "cancel", item_id: "btnFermer", name: "Fermer" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// -- Gestionnaires d'evenements, un par item_id de bouton --------
|
||||
btnLivret: { mouse_down: function (dialog) { dialog.end(A.LIVRET); } },
|
||||
btnNUp: { mouse_down: function (dialog) { dialog.end(A.NUP); } },
|
||||
btnDecoupe: { mouse_down: function (dialog) { dialog.end(A.DECOUPE); } },
|
||||
btnMarges: { mouse_down: function (dialog) { dialog.end(A.MARGES); } },
|
||||
btnReperes: { mouse_down: function (dialog) { dialog.end(A.REPERES); } },
|
||||
btnAuto: { mouse_down: function (dialog) { dialog.end(A.AUTO); } }
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Affiche un message indiquant qu'un module n'est pas encore implemente.
|
||||
*/
|
||||
CDImp.UI._moduleAVenir = function (nomModule) {
|
||||
CDImp.Util.info("Module \"" + nomModule + "\" : en cours de developpement.\nDisponible dans une prochaine version de la suite d'imposition.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Point d'entree principal : ouvre le panneau de controle, puis route vers
|
||||
* le module choisi par l'utilisateur. Le document actif (celui depuis lequel
|
||||
* le menu a ete invoque) est transmis aux modules afin qu'ils n'aient pas a
|
||||
* deviner quel document cibler.
|
||||
*
|
||||
* @param {Doc} [docCourant] document actif, transmis via "this" par le menu
|
||||
*/
|
||||
CDImp.UI.ouvrirPanneauPrincipal = function (docCourant) {
|
||||
var doc;
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(docCourant);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Veuillez ouvrir un document PDF avant de lancer l'imposition.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Licence && !CDImp.Licence.verifierEtBloquerSiInvalide()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oDialogue = CDImp.UI._construireDialoguePrincipal();
|
||||
var resultat;
|
||||
try {
|
||||
resultat = app.execDialog(oDialogue);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Impossible d'ouvrir le panneau d'imposition : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var routes = [
|
||||
{ action: CDImp.UI.ACTIONS.LIVRET, module: "Livret", nom: "Creer un livret" },
|
||||
{ action: CDImp.UI.ACTIONS.NUP, module: "NUp", nom: "N-Up / Step & Repeat" },
|
||||
{ action: CDImp.UI.ACTIONS.DECOUPE, module: "Decoupe", nom: "Decoupe & reassemblage" },
|
||||
{ action: CDImp.UI.ACTIONS.MARGES, module: "Marges", nom: "Marges & cadrages" },
|
||||
{ action: CDImp.UI.ACTIONS.REPERES, module: "Reperes", nom: "Reperes, textes, numerotation" },
|
||||
{ action: CDImp.UI.ACTIONS.AUTO, module: "Auto", nom: "Automatisation" }
|
||||
];
|
||||
|
||||
for (var i = 0; i < routes.length; i++) {
|
||||
if (routes[i].action === resultat) {
|
||||
var mod = CDImp[routes[i].module];
|
||||
if (mod && mod.lancer) {
|
||||
mod.lancer(doc);
|
||||
} else {
|
||||
CDImp.UI._moduleAVenir(routes[i].nom);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fermeture / Annulation : rien a faire.
|
||||
};
|
||||
318
acrobat-plugin/src/Imposition-02-Livret.js
Executable file
318
acrobat-plugin/src/Imposition-02-Livret.js
Executable file
@@ -0,0 +1,318 @@
|
||||
// Imposition-02-Livret.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 2 : Creer un livret / Delivretiser (signature de cahier, piqure a cheval)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// ATTENTION TECHNIQUE - a lire avant utilisation en production :
|
||||
// Le placement des pages source sur les planches composites repose sur
|
||||
// CDImp.Util.placerPageDansRect()/extraireRegionPage() (voir Core.js), qui
|
||||
// utilisent la technique "template + recadrage de CropBox" standard en
|
||||
// JavaScript pur pour Acrobat (sans plugin natif). Cette technique n'a pas
|
||||
// pu etre executee/verifiee dans une vraie session Acrobat depuis cet
|
||||
// environnement de developpement (Acrobat n'y est pas installe) : a tester
|
||||
// sur un PDF reel avant tout usage en production.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-02-Livret.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Livret = CDImp.Livret || {};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Calcul de l'ordre des pages (imposition en cahier unique, piqure a cheval)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Calcule l'imbrication des pages pour un cahier unique (selle/pliage central).
|
||||
* Fonction symetrique : utilisee aussi bien pour imposer (Page logique ->
|
||||
* position sur planche) que pour delivretiser (position sur planche -> page
|
||||
* logique), puisque l'imposition en cahier simple est sa propre inverse au
|
||||
* niveau de la formule (seul le sens d'utilisation change).
|
||||
*
|
||||
* Pour N pages (multiple de 4), chaque feuille porte 4 pages : 2 au recto,
|
||||
* 2 au verso. Exemple pour N=8 :
|
||||
* Feuille 1 - recto : (8 | 1) verso : (2 | 7)
|
||||
* Feuille 2 - recto : (6 | 3) verso : (4 | 5)
|
||||
*
|
||||
* @param {Number} nPages nombre total de pages (doit etre un multiple de 4)
|
||||
* @returns {Array} liste de planches, dans l'ordre d'impression :
|
||||
* [{ feuille: 1, face: "recto", gauche: 8, droite: 1 }, ...]
|
||||
* "gauche"/"droite" sont des numeros de page 1-based du document source.
|
||||
*/
|
||||
CDImp.Livret.calculerOrdre = function (nPages) {
|
||||
if (nPages % 4 !== 0) {
|
||||
throw new Error("calculerOrdre : le nombre de pages (" + nPages + ") doit etre un multiple de 4.");
|
||||
}
|
||||
var nFeuilles = nPages / 4;
|
||||
var planches = [];
|
||||
for (var s = 0; s < nFeuilles; s++) {
|
||||
planches.push({ feuille: s + 1, face: "recto", gauche: nPages - 2 * s, droite: 2 * s + 1 });
|
||||
planches.push({ feuille: s + 1, face: "verso", gauche: 2 * s + 2, droite: nPages - 2 * s - 1 });
|
||||
}
|
||||
return planches;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Ajout de pages blanches pour atteindre un multiple de 4
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Insere nManque pages blanches dans doc, a la position demandee.
|
||||
* Les pages blanches reprennent le format (largeur/hauteur) de la premiere
|
||||
* page du document.
|
||||
*
|
||||
* @param {Doc} doc document a modifier (modification en place)
|
||||
* @param {Number} nManque nombre de pages blanches a ajouter
|
||||
* @param {String} position "debut" | "fin" | "apres_couverture"
|
||||
*/
|
||||
CDImp.Livret.ajouterPagesBlanches = function (doc, nManque, position) {
|
||||
if (nManque <= 0) {
|
||||
return;
|
||||
}
|
||||
var boxRef = doc.getPageBox({ nPage: 0, cBox: "Crop" });
|
||||
var largeur = Math.abs(boxRef[2] - boxRef[0]);
|
||||
var hauteur = Math.abs(boxRef[3] - boxRef[1]);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
for (var k = 0; k < nManque; k++) {
|
||||
var idxInsertion;
|
||||
switch (position) {
|
||||
case "debut":
|
||||
idxInsertion = 0;
|
||||
break;
|
||||
case "apres_couverture":
|
||||
idxInsertion = 1;
|
||||
break;
|
||||
case "fin":
|
||||
default:
|
||||
idxInsertion = doc.numPages; // toujours recalcule : ajoute en fin
|
||||
break;
|
||||
}
|
||||
doc.newPage({ nPage: idxInsertion, width: largeur, height: hauteur });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Demande a l'utilisateur ou inserer les pages blanches manquantes, via un
|
||||
* menu contextuel simple (app.popUpMenu, API stable et bien documentee,
|
||||
* preferee ici a un second execDialog pour limiter les risques sur un choix
|
||||
* aussi simple).
|
||||
*
|
||||
* @returns {String|null} "debut" | "fin" | "apres_couverture", ou null si
|
||||
* l'utilisateur annule.
|
||||
*/
|
||||
CDImp.Livret._demanderPositionPagesBlanches = function (nManque) {
|
||||
var choix = app.popUpMenu(
|
||||
{ cName: "A la fin du document (" + nManque + " page(s))", cReturn: "fin" },
|
||||
{ cName: "Au debut du document (" + nManque + " page(s))", cReturn: "debut" },
|
||||
{ cName: "Juste apres la couverture (page 1)", cReturn: "apres_couverture" }
|
||||
);
|
||||
return choix || null;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Construction du document imposes (sens direct : pages -> livret)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Construit le document de sortie : une page composite (format double, en
|
||||
* paysage) par planche recto/verso, avec les deux pages source positionnees
|
||||
* cote a cote.
|
||||
*
|
||||
* @param {Doc} srcDoc document source (deja complete a un multiple de 4 pages)
|
||||
* @param {Array} planches resultat de CDImp.Livret.calculerOrdre()
|
||||
* @param {Number} creepMm compensation de chasse en mm, appliquee
|
||||
* progressivement vers l'interieur du cahier (0 = desactive)
|
||||
* @returns {Doc} le nouveau document compose
|
||||
*/
|
||||
CDImp.Livret.construireDocument = function (srcDoc, planches, creepMm) {
|
||||
var boxSrc = srcDoc.getPageBox({ nPage: 0, cBox: "Crop" });
|
||||
var largeurSrc = Math.abs(boxSrc[2] - boxSrc[0]);
|
||||
var hauteurSrc = Math.abs(boxSrc[3] - boxSrc[1]);
|
||||
var largeurDest = largeurSrc * 2;
|
||||
var hauteurDest = hauteurSrc;
|
||||
var nFeuilles = planches.length / 2;
|
||||
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
destDoc.newPage({ nPage: 0, width: largeurDest, height: hauteurDest });
|
||||
for (var k = 1; k < planches.length; k++) {
|
||||
destDoc.newPage({ nPage: k, width: largeurDest, height: hauteurDest });
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < planches.length; i++) {
|
||||
var planche = planches[i];
|
||||
|
||||
// Decalage de chasse (creep) : croissant en s'eloignant du centre du
|
||||
// cahier vers l'exterieur, applique symetriquement gauche/droite.
|
||||
var decalageCreepPt = creepMm
|
||||
? CDImp.Util.mmToPt(creepMm) * (nFeuilles - planche.feuille)
|
||||
: 0;
|
||||
|
||||
CDImp.Util.placerPageDansRect(srcDoc, planche.gauche, destDoc, i,
|
||||
[decalageCreepPt, 0, decalageCreepPt + largeurSrc, hauteurSrc]);
|
||||
CDImp.Util.placerPageDansRect(srcDoc, planche.droite, destDoc, i,
|
||||
[largeurSrc - decalageCreepPt, 0, largeurDest - decalageCreepPt, hauteurSrc]);
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Delivretisation (sens inverse : livret imposes -> ordre de lecture normal)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Reconstitue l'ordre de lecture normal d'un PDF imposé en cahier piqûre a
|
||||
* cheval : chaque page du document source est une planche double (recto ou
|
||||
* verso) contenant deux pages logiques cote a cote, dans l'ordre produit par
|
||||
* CDImp.Livret.construireDocument(). On reutilise calculerOrdre() pour
|
||||
* retrouver, pour chaque planche, les numeros de page logique a replacer a
|
||||
* gauche et a droite, puis on extrait chaque moitie vers sa position finale.
|
||||
*
|
||||
* Limite connue : ne compense pas une eventuelle chasse (creep) appliquee
|
||||
* lors de l'imposition d'origine (les pages reconstituees seront legerement
|
||||
* decalees si un creep non nul avait ete utilise).
|
||||
*
|
||||
* @param {Doc} doc document imposes (planches doubles), document actif si omis
|
||||
*/
|
||||
CDImp.Livret.delivretiser = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var nPlanches = doc.numPages;
|
||||
if (nPlanches % 2 !== 0) {
|
||||
CDImp.Util.erreur("Delivretiser : le document doit contenir un nombre pair de planches\n(une planche recto + une planche verso par feuille).");
|
||||
return;
|
||||
}
|
||||
var nPagesLogiques = nPlanches * 2;
|
||||
|
||||
var planches;
|
||||
try {
|
||||
planches = CDImp.Livret.calculerOrdre(nPagesLogiques);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var boxRef = doc.getPageBox({ nPage: 0, cBox: "Crop" });
|
||||
var largeurPlanche = Math.abs(boxRef[2] - boxRef[0]);
|
||||
var hauteur = Math.abs(boxRef[3] - boxRef[1]);
|
||||
var largeurDemiPage = largeurPlanche / 2;
|
||||
|
||||
var destDoc;
|
||||
try {
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
destDoc.newPage({ nPage: 0, width: largeurDemiPage, height: hauteur });
|
||||
for (var k = 1; k < nPagesLogiques; k++) {
|
||||
destDoc.newPage({ nPage: k, width: largeurDemiPage, height: hauteur });
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < planches.length; i++) {
|
||||
var planche = planches[i];
|
||||
var rectGauche = [0, 0, largeurDemiPage, hauteur];
|
||||
var rectDroite = [largeurDemiPage, 0, largeurPlanche, hauteur];
|
||||
|
||||
CDImp.Util.extraireRegionPage(doc, i + 1, rectGauche, destDoc, planche.gauche - 1);
|
||||
CDImp.Util.extraireRegionPage(doc, i + 1, rectDroite, destDoc, planche.droite - 1);
|
||||
}
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de la delivretisation : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Livret.delivretiser", {});
|
||||
}
|
||||
|
||||
CDImp.Util.info("Delivretisation terminee (" + nPagesLogiques + " pages reconstituees).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree du module (appele depuis le panneau principal, Module 1)
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Livret.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var sens = app.popUpMenu(
|
||||
{ cName: "Creer un livret (imposition)", cReturn: "imposer" },
|
||||
{ cName: "Delivretiser (revenir a l'ordre de lecture)", cReturn: "delivretiser" }
|
||||
);
|
||||
if (!sens) {
|
||||
return; // annulation
|
||||
}
|
||||
|
||||
if (sens === "delivretiser") {
|
||||
CDImp.Livret.delivretiser(doc);
|
||||
return;
|
||||
}
|
||||
|
||||
var nPages = doc.numPages;
|
||||
var reste = nPages % 4;
|
||||
|
||||
if (reste !== 0) {
|
||||
var nManque = 4 - reste;
|
||||
var position = CDImp.Livret._demanderPositionPagesBlanches(nManque);
|
||||
if (!position) {
|
||||
return; // annulation utilisateur
|
||||
}
|
||||
CDImp.Livret.ajouterPagesBlanches(doc, nManque, position);
|
||||
nPages = doc.numPages;
|
||||
}
|
||||
|
||||
var creepMm = CDImp.Util.demanderNombre(
|
||||
"Compensation de chasse (creep) en mm par feuille (0 = aucune) :",
|
||||
"Creer un livret",
|
||||
0
|
||||
);
|
||||
if (creepMm === null) {
|
||||
return; // annulation utilisateur
|
||||
}
|
||||
|
||||
var planches = CDImp.Livret.calculerOrdre(nPages);
|
||||
|
||||
var destDoc;
|
||||
try {
|
||||
destDoc = CDImp.Livret.construireDocument(doc, planches, creepMm);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de la construction du livret : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Livret.imposer", { creepMm: creepMm });
|
||||
}
|
||||
|
||||
CDImp.Util.info("Livret cree avec succes (" + planches.length + " planches).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Variante directe sans dialogues, utilisee par le Module 7 (Automatisation)
|
||||
* pour rejouer une action enregistree sur un nouveau document. Ne gere pas
|
||||
* l'ajout de pages blanches (le document doit deja etre un multiple de 4).
|
||||
*/
|
||||
CDImp.Livret.executerAvecParams = function (doc, params) {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
var nPages = doc.numPages;
|
||||
if (nPages % 4 !== 0) {
|
||||
CDImp.Util.erreur("Repeter l'action : le document (" + nPages + " pages) n'est pas un multiple de 4.\nUtilisez le module Livret manuellement pour ajouter les pages blanches.");
|
||||
return;
|
||||
}
|
||||
var planches = CDImp.Livret.calculerOrdre(nPages);
|
||||
var destDoc = CDImp.Livret.construireDocument(doc, planches, params.creepMm || 0);
|
||||
CDImp.Util.info("Livret recree avec succes (" + planches.length + " planches).");
|
||||
return destDoc;
|
||||
};
|
||||
197
acrobat-plugin/src/Imposition-03-NUp.js
Executable file
197
acrobat-plugin/src/Imposition-03-NUp.js
Executable file
@@ -0,0 +1,197 @@
|
||||
// Imposition-03-NUp.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 3 : N-Up & Step and Repeat (amalgame et multi-poses)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// Repose sur CDImp.Util.placerPageDansRect() (technique template + CropBox,
|
||||
// voir avertissement dans Imposition-00-Core.js) pour positionner ET mettre
|
||||
// a l'echelle chaque page source dans sa cellule de grille. A tester dans
|
||||
// Acrobat Pro reel avant usage en production.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-03-NUp.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.NUp = CDImp.NUp || {};
|
||||
|
||||
/**
|
||||
* Construit une grille de nLignes x nColonnes sur des feuilles au format
|
||||
* (largeurFeuilleMm x hauteurFeuilleMm), en mode "n-up" (pages successives
|
||||
* du document source) ou "repeat" (une seule page dupliquee sur la grille).
|
||||
*
|
||||
* @param {Doc} srcDoc document source
|
||||
* @param {Object} p parametres :
|
||||
* nLignes, nColonnes {Number}
|
||||
* largeurFeuilleMm, hauteurFeuilleMm {Number}
|
||||
* gouttiereMm {Number} espace entre les poses
|
||||
* margeMm {Number} marge technique autour de la feuille
|
||||
* mode {String} "nup" | "repeat"
|
||||
* nPageRepeat {Number} page 1-based a dupliquer (mode "repeat" uniquement)
|
||||
* @returns {Doc} le nouveau document compose
|
||||
*/
|
||||
CDImp.NUp.construireGrille = function (srcDoc, p) {
|
||||
var feuilleW = CDImp.Util.mmToPt(p.largeurFeuilleMm);
|
||||
var feuilleH = CDImp.Util.mmToPt(p.hauteurFeuilleMm);
|
||||
var margePt = CDImp.Util.mmToPt(p.margeMm);
|
||||
var goutPt = CDImp.Util.mmToPt(p.gouttiereMm);
|
||||
|
||||
var cellW = (feuilleW - 2 * margePt - (p.nColonnes - 1) * goutPt) / p.nColonnes;
|
||||
var cellH = (feuilleH - 2 * margePt - (p.nLignes - 1) * goutPt) / p.nLignes;
|
||||
if (cellW <= 0 || cellH <= 0) {
|
||||
throw new Error("Grille N-Up : la feuille est trop petite pour " + p.nLignes + " x " + p.nColonnes + " avec ces marges/gouttieres.");
|
||||
}
|
||||
|
||||
// Page de reference pour le ratio d'echelle (premiere page, ou page a
|
||||
// repeter en mode Step & Repeat).
|
||||
var nPageRef = (p.mode === "repeat") ? p.nPageRepeat : 1;
|
||||
var boxRef = srcDoc.getPageBox({ nPage: nPageRef - 1, cBox: "Crop" });
|
||||
var largeurSrc = Math.abs(boxRef[2] - boxRef[0]);
|
||||
var hauteurSrc = Math.abs(boxRef[3] - boxRef[1]);
|
||||
var echelle = Math.min(cellW / largeurSrc, cellH / hauteurSrc);
|
||||
var largeurMise = largeurSrc * echelle;
|
||||
var hauteurMise = hauteurSrc * echelle;
|
||||
|
||||
var nParFeuille = p.nLignes * p.nColonnes;
|
||||
var nFeuilles = (p.mode === "repeat") ? 1 : Math.ceil(srcDoc.numPages / nParFeuille);
|
||||
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
destDoc.newPage({ nPage: 0, width: feuilleW, height: feuilleH });
|
||||
for (var k = 1; k < nFeuilles; k++) {
|
||||
destDoc.newPage({ nPage: k, width: feuilleW, height: feuilleH });
|
||||
}
|
||||
});
|
||||
|
||||
for (var s = 0; s < nFeuilles; s++) {
|
||||
for (var r = 0; r < p.nLignes; r++) {
|
||||
for (var c = 0; c < p.nColonnes; c++) {
|
||||
var idxGrille = r * p.nColonnes + c;
|
||||
var nSrcPage;
|
||||
if (p.mode === "repeat") {
|
||||
nSrcPage = p.nPageRepeat;
|
||||
} else {
|
||||
var idxGlobal = s * nParFeuille + idxGrille;
|
||||
if (idxGlobal >= srcDoc.numPages) {
|
||||
continue; // cellule vide en fin de grille
|
||||
}
|
||||
nSrcPage = idxGlobal + 1;
|
||||
}
|
||||
|
||||
var cellX = margePt + c * (cellW + goutPt);
|
||||
// r=0 correspond a la rangee du haut visuellement.
|
||||
var cellYBas = feuilleH - margePt - (r + 1) * cellH - r * goutPt;
|
||||
var offsetX = cellX + (cellW - largeurMise) / 2;
|
||||
var offsetY = cellYBas + (cellH - hauteurMise) / 2;
|
||||
|
||||
CDImp.Util.placerPageDansRect(srcDoc, nSrcPage, destDoc, s,
|
||||
[offsetX, offsetY, offsetX + largeurMise, offsetY + hauteurMise]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Demande le format de feuille cible (standard ou personnalise), en mm.
|
||||
* @returns {Object|null} { largeurMm, hauteurMm }, ou null si annule
|
||||
*/
|
||||
CDImp.NUp._demanderFormatFeuille = function () {
|
||||
var choix = app.popUpMenu(
|
||||
{ cName: "A4 (210 x 297 mm)", cReturn: "A4" },
|
||||
{ cName: "A3 (297 x 420 mm)", cReturn: "A3" },
|
||||
{ cName: "SRA3 (320 x 450 mm)", cReturn: "SRA3" },
|
||||
{ cName: "SRA4 (225 x 320 mm)", cReturn: "SRA4" },
|
||||
{ cName: "Letter (215.9 x 279.4 mm)", cReturn: "LETTER" },
|
||||
{ cName: "Personnalise...", cReturn: "PERSO" }
|
||||
);
|
||||
if (!choix) {
|
||||
return null;
|
||||
}
|
||||
if (choix !== "PERSO") {
|
||||
var f = CDImp.Util.FORMATS_MM[choix];
|
||||
return { largeurMm: f[0], hauteurMm: f[1] };
|
||||
}
|
||||
var largeurMm = CDImp.Util.demanderNombre("Largeur de la feuille (mm) :", "Format personnalise", 320);
|
||||
if (largeurMm === null) { return null; }
|
||||
var hauteurMm = CDImp.Util.demanderNombre("Hauteur de la feuille (mm) :", "Format personnalise", 450);
|
||||
if (hauteurMm === null) { return null; }
|
||||
return { largeurMm: largeurMm, hauteurMm: hauteurMm };
|
||||
};
|
||||
|
||||
CDImp.NUp.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = app.popUpMenu(
|
||||
{ cName: "Grille N-Up (pages successives du document)", cReturn: "nup" },
|
||||
{ cName: "Repetition - Step & Repeat (dupliquer une page)", cReturn: "repeat" }
|
||||
);
|
||||
if (!mode) { return; }
|
||||
|
||||
var nLignes = CDImp.Util.demanderNombre("Nombre de lignes :", "N-Up / Step & Repeat", 2);
|
||||
if (nLignes === null) { return; }
|
||||
var nColonnes = CDImp.Util.demanderNombre("Nombre de colonnes :", "N-Up / Step & Repeat", 2);
|
||||
if (nColonnes === null) { return; }
|
||||
|
||||
var formatFeuille = CDImp.NUp._demanderFormatFeuille();
|
||||
if (!formatFeuille) { return; }
|
||||
|
||||
var gouttiereMm = CDImp.Util.demanderNombre("Gouttiere entre les poses (mm) :", "N-Up / Step & Repeat", 4);
|
||||
if (gouttiereMm === null) { return; }
|
||||
var margeMm = CDImp.Util.demanderNombre("Marge technique autour de la feuille (mm) :", "N-Up / Step & Repeat", 5);
|
||||
if (margeMm === null) { return; }
|
||||
|
||||
var nPageRepeat = 1;
|
||||
if (mode === "repeat") {
|
||||
nPageRepeat = CDImp.Util.demanderNombre("Numero de la page a dupliquer :", "Step & Repeat", doc.pageNum + 1);
|
||||
if (nPageRepeat === null) { return; }
|
||||
if (nPageRepeat < 1 || nPageRepeat > doc.numPages) {
|
||||
CDImp.Util.erreur("Page invalide : " + nPageRepeat);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var params = {
|
||||
nLignes: nLignes,
|
||||
nColonnes: nColonnes,
|
||||
largeurFeuilleMm: formatFeuille.largeurMm,
|
||||
hauteurFeuilleMm: formatFeuille.hauteurMm,
|
||||
gouttiereMm: gouttiereMm,
|
||||
margeMm: margeMm,
|
||||
mode: mode,
|
||||
nPageRepeat: nPageRepeat
|
||||
};
|
||||
|
||||
var destDoc;
|
||||
try {
|
||||
destDoc = CDImp.NUp.construireGrille(doc, params);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de la construction de la grille : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("NUp.executer", params);
|
||||
}
|
||||
|
||||
CDImp.Util.info("Mise en page terminee (" + destDoc.numPages + " feuille(s)).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Variante directe sans dialogues (Module 7 - Automatisation).
|
||||
*/
|
||||
CDImp.NUp.executerAvecParams = function (doc, params) {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
var destDoc = CDImp.NUp.construireGrille(doc, params);
|
||||
CDImp.Util.info("Mise en page recreee avec succes (" + destDoc.numPages + " feuille(s)).");
|
||||
return destDoc;
|
||||
};
|
||||
222
acrobat-plugin/src/Imposition-04-Decoupe.js
Executable file
222
acrobat-plugin/src/Imposition-04-Decoupe.js
Executable file
@@ -0,0 +1,222 @@
|
||||
// Imposition-04-Decoupe.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 4 : Decoupe et reassemblage de pages
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// Repose sur CDImp.Util.extraireRegionPage() / placerPageDansRect() (voir
|
||||
// avertissement dans Imposition-00-Core.js). A tester dans Acrobat Pro reel
|
||||
// avant usage en production.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-04-Decoupe.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Decoupe = CDImp.Decoupe || {};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Couper les pages en deux (Split)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Coupe chaque page de srcDoc en deux moities independantes et retourne un
|
||||
* nouveau document contenant 2x plus de pages.
|
||||
*
|
||||
* @param {Doc} srcDoc
|
||||
* @param {String} axe "vertical" (gauche/droite) | "horizontal" (haut/bas)
|
||||
* @returns {Doc} nouveau document
|
||||
*/
|
||||
CDImp.Decoupe.couperPages = function (srcDoc, axe) {
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
});
|
||||
|
||||
var nDestPage = 0;
|
||||
for (var s = 0; s < srcDoc.numPages; s++) {
|
||||
var box = srcDoc.getPageBox({ nPage: s, cBox: "Crop" });
|
||||
var w = Math.abs(box[2] - box[0]);
|
||||
var h = Math.abs(box[3] - box[1]);
|
||||
|
||||
var demis; // [{rect, largeur, hauteur}, ...] dans l'ordre de lecture
|
||||
if (axe === "horizontal") {
|
||||
demis = [
|
||||
{ rect: [0, h / 2, w, h], largeur: w, hauteur: h / 2 }, // haut
|
||||
{ rect: [0, 0, w, h / 2], largeur: w, hauteur: h / 2 } // bas
|
||||
];
|
||||
} else {
|
||||
demis = [
|
||||
{ rect: [0, 0, w / 2, h], largeur: w / 2, hauteur: h }, // gauche
|
||||
{ rect: [w / 2, 0, w, h], largeur: w / 2, hauteur: h } // droite
|
||||
];
|
||||
}
|
||||
|
||||
for (var d = 0; d < demis.length; d++) {
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc.newPage({ nPage: nDestPage, width: demis[d].largeur, height: demis[d].hauteur });
|
||||
});
|
||||
CDImp.Util.extraireRegionPage(srcDoc, s + 1, demis[d].rect, destDoc, nDestPage);
|
||||
nDestPage++;
|
||||
}
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Inversion de l'ordre des pages
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Retourne un nouveau document avec les pages de srcDoc dans l'ordre inverse.
|
||||
*/
|
||||
CDImp.Decoupe.inverserOrdre = function (srcDoc) {
|
||||
var n = srcDoc.numPages;
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
});
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
var nSrcPage = n - i; // 1-based, en partant de la derniere page
|
||||
var box = srcDoc.getPageBox({ nPage: nSrcPage - 1, cBox: "Crop" });
|
||||
var w = Math.abs(box[2] - box[0]);
|
||||
var h = Math.abs(box[3] - box[1]);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc.newPage({ nPage: i, width: w, height: h });
|
||||
});
|
||||
CDImp.Util.placerPageDansRect(srcDoc, nSrcPage, destDoc, i, [0, 0, w, h]);
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Reassemblage par motif (mélange par blocs)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Reordonne les pages de srcDoc par blocs, selon un motif comme "1,3,2,4"
|
||||
* (1-based, a l'interieur de chaque bloc). La taille de bloc est la longueur
|
||||
* du motif ; le nombre de pages doit en etre un multiple exact.
|
||||
*
|
||||
* @param {Doc} srcDoc
|
||||
* @param {String} motifStr ex: "1,3,2,4"
|
||||
* @returns {Doc} nouveau document reordonne
|
||||
*/
|
||||
CDImp.Decoupe.reassembler = function (srcDoc, motifStr) {
|
||||
var motif = motifStr.split(",").map(function (s) { return parseInt(s.trim(), 10); });
|
||||
var taille = motif.length;
|
||||
if (taille === 0 || motif.some(function (m) { return isNaN(m) || m < 1 || m > taille; })) {
|
||||
throw new Error("Motif invalide : \"" + motifStr + "\". Attendu une liste de positions 1-based, ex: 1,3,2,4");
|
||||
}
|
||||
if (srcDoc.numPages % taille !== 0) {
|
||||
throw new Error("Le document (" + srcDoc.numPages + " pages) n'est pas un multiple de la taille de bloc (" + taille + ").");
|
||||
}
|
||||
|
||||
var nBlocs = srcDoc.numPages / taille;
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
});
|
||||
|
||||
var nDestPage = 0;
|
||||
for (var b = 0; b < nBlocs; b++) {
|
||||
for (var k = 0; k < taille; k++) {
|
||||
var nSrcPage = b * taille + motif[k]; // 1-based
|
||||
var box = srcDoc.getPageBox({ nPage: nSrcPage - 1, cBox: "Crop" });
|
||||
var w = Math.abs(box[2] - box[0]);
|
||||
var h = Math.abs(box[3] - box[1]);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc.newPage({ nPage: nDestPage, width: w, height: h });
|
||||
});
|
||||
CDImp.Util.placerPageDansRect(srcDoc, nSrcPage, destDoc, nDestPage, [0, 0, w, h]);
|
||||
nDestPage++;
|
||||
}
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree du module
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Decoupe.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var action = app.popUpMenu(
|
||||
{ cName: "Couper les pages en deux (Split)", cReturn: "split" },
|
||||
{ cName: "Inverser l'ordre des pages", cReturn: "reverse" },
|
||||
{ cName: "Reassembler par motif (Shuffle)", cReturn: "shuffle" }
|
||||
);
|
||||
if (!action) { return; }
|
||||
|
||||
var destDoc, params;
|
||||
try {
|
||||
switch (action) {
|
||||
case "split":
|
||||
var axe = app.popUpMenu(
|
||||
{ cName: "Vertical (gauche / droite)", cReturn: "vertical" },
|
||||
{ cName: "Horizontal (haut / bas)", cReturn: "horizontal" }
|
||||
);
|
||||
if (!axe) { return; }
|
||||
params = { action: "split", axe: axe };
|
||||
destDoc = CDImp.Decoupe.couperPages(doc, axe);
|
||||
break;
|
||||
|
||||
case "reverse":
|
||||
params = { action: "reverse" };
|
||||
destDoc = CDImp.Decoupe.inverserOrdre(doc);
|
||||
break;
|
||||
|
||||
case "shuffle":
|
||||
var motifStr = app.response({
|
||||
cQuestion: "Motif de reassemblage par bloc (positions 1-based separees par des virgules) :",
|
||||
cTitle: "Reassembler par motif",
|
||||
cDefault: "1,3,2,4"
|
||||
});
|
||||
if (motifStr === null) { return; }
|
||||
params = { action: "shuffle", motif: motifStr };
|
||||
destDoc = CDImp.Decoupe.reassembler(doc, motifStr);
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Decoupe.executer", params);
|
||||
}
|
||||
|
||||
CDImp.Util.info("Operation terminee (" + destDoc.numPages + " page(s)).\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Variante directe sans dialogues (Module 7 - Automatisation).
|
||||
*/
|
||||
CDImp.Decoupe.executerAvecParams = function (doc, params) {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
var destDoc;
|
||||
switch (params.action) {
|
||||
case "split":
|
||||
destDoc = CDImp.Decoupe.couperPages(doc, params.axe);
|
||||
break;
|
||||
case "reverse":
|
||||
destDoc = CDImp.Decoupe.inverserOrdre(doc);
|
||||
break;
|
||||
case "shuffle":
|
||||
destDoc = CDImp.Decoupe.reassembler(doc, params.motif);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Action inconnue : " + params.action);
|
||||
}
|
||||
CDImp.Util.info("Operation recreee avec succes (" + destDoc.numPages + " page(s)).");
|
||||
return destDoc;
|
||||
};
|
||||
233
acrobat-plugin/src/Imposition-05-Marges.js
Executable file
233
acrobat-plugin/src/Imposition-05-Marges.js
Executable file
@@ -0,0 +1,233 @@
|
||||
// Imposition-05-Marges.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 5 : Gestion des marges et cadrages (Page Boxes)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// ajouterEspaceBlanc() et harmoniserBoites() modifient le document EN PLACE
|
||||
// (simple edition de boites, operation legere et fiable). deplacerContenu()
|
||||
// doit en revanche reconstruire les pages via la technique template+CropBox
|
||||
// (voir avertissement dans Imposition-00-Core.js) car deplacer du contenu
|
||||
// existant n'est pas possible par simple edition de boite.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-05-Marges.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Marges = CDImp.Marges || {};
|
||||
|
||||
/**
|
||||
* Resout la liste d'indices de page (0-based) a traiter.
|
||||
* @param {Doc} doc
|
||||
* @param {String} portee "toutes" | "courante"
|
||||
*/
|
||||
CDImp.Marges._resoudrePortee = function (doc, portee) {
|
||||
if (portee === "courante") {
|
||||
return [doc.pageNum];
|
||||
}
|
||||
var indices = [];
|
||||
for (var i = 0; i < doc.numPages; i++) {
|
||||
indices.push(i);
|
||||
}
|
||||
return indices;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Ajouter de l'espace blanc autour du contenu
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Agrandit la MediaBox et la CropBox de chaque page concernee sans toucher
|
||||
* au contenu existant, en ajoutant les marges donnees (en mm) sur chaque
|
||||
* cote.
|
||||
*
|
||||
* @param {Doc} doc modifie en place
|
||||
* @param {Object} margesMm { haut, bas, gauche, droite } en mm
|
||||
* @param {String} portee "toutes" | "courante"
|
||||
*/
|
||||
CDImp.Marges.ajouterEspaceBlanc = function (doc, margesMm, portee) {
|
||||
var hautPt = CDImp.Util.mmToPt(margesMm.haut);
|
||||
var basPt = CDImp.Util.mmToPt(margesMm.bas);
|
||||
var gauchePt = CDImp.Util.mmToPt(margesMm.gauche);
|
||||
var droitePt = CDImp.Util.mmToPt(margesMm.droite);
|
||||
var indices = CDImp.Marges._resoudrePortee(doc, portee);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
for (var k = 0; k < indices.length; k++) {
|
||||
var i = indices[k];
|
||||
var crop = doc.getPageBox({ nPage: i, cBox: "Crop" });
|
||||
var nouveauCrop = [crop[0] - gauchePt, crop[1] - basPt, crop[2] + droitePt, crop[3] + hautPt];
|
||||
doc.setPageBoxes({ nPage: i, cBox: "Crop", rBox: nouveauCrop });
|
||||
doc.setPageBoxes({ nPage: i, cBox: "Media", rBox: nouveauCrop });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Deplacer le contenu d'une page
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Construit un nouveau document ou le contenu de chaque page concernee est
|
||||
* decale de (dxMm, dyMm) par rapport a sa position d'origine (les pages non
|
||||
* concernees sont recopiees telles quelles).
|
||||
*
|
||||
* @param {Doc} srcDoc
|
||||
* @param {Number} dxMm decalage horizontal en mm (positif = vers la droite)
|
||||
* @param {Number} dyMm decalage vertical en mm (positif = vers le haut)
|
||||
* @param {String} portee "toutes" | "courante"
|
||||
* @returns {Doc} nouveau document
|
||||
*/
|
||||
CDImp.Marges.deplacerContenu = function (srcDoc, dxMm, dyMm, portee) {
|
||||
var dxPt = CDImp.Util.mmToPt(dxMm);
|
||||
var dyPt = CDImp.Util.mmToPt(dyMm);
|
||||
var indicesConcernes = CDImp.Marges._resoudrePortee(srcDoc, portee);
|
||||
var ensembleConcernes = {};
|
||||
for (var k = 0; k < indicesConcernes.length; k++) {
|
||||
ensembleConcernes[indicesConcernes[k]] = true;
|
||||
}
|
||||
|
||||
var destDoc;
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc = new Doc();
|
||||
});
|
||||
|
||||
for (var i = 0; i < srcDoc.numPages; i++) {
|
||||
var box = srcDoc.getPageBox({ nPage: i, cBox: "Crop" });
|
||||
var w = Math.abs(box[2] - box[0]);
|
||||
var h = Math.abs(box[3] - box[1]);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
destDoc.newPage({ nPage: i, width: w, height: h });
|
||||
});
|
||||
|
||||
var decalX = ensembleConcernes[i] ? dxPt : 0;
|
||||
var decalY = ensembleConcernes[i] ? dyPt : 0;
|
||||
CDImp.Util.placerPageDansRect(srcDoc, i + 1, destDoc, i, [decalX, decalY, decalX + w, decalY + h]);
|
||||
}
|
||||
|
||||
return destDoc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Harmonisation des boites (Media/Crop/Bleed/Trim)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Pour chaque page concernee, force les 4 boites (Media, Crop, Bleed, Trim)
|
||||
* a coincider avec la valeur actuelle de la boite de reference cBoxRef.
|
||||
*
|
||||
* @param {Doc} doc modifie en place
|
||||
* @param {String} cBoxRef "Media" | "Crop" | "Bleed" | "Trim"
|
||||
* @param {String} portee "toutes" | "courante"
|
||||
*/
|
||||
CDImp.Marges.harmoniserBoites = function (doc, cBoxRef, portee) {
|
||||
var indices = CDImp.Marges._resoudrePortee(doc, portee);
|
||||
var toutesBoites = ["Media", "Crop", "Bleed", "Trim"];
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
for (var k = 0; k < indices.length; k++) {
|
||||
var i = indices[k];
|
||||
var rectRef = doc.getPageBox({ nPage: i, cBox: cBoxRef });
|
||||
for (var b = 0; b < toutesBoites.length; b++) {
|
||||
doc.setPageBoxes({ nPage: i, cBox: toutesBoites[b], rBox: rectRef });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree du module
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Marges.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var action = app.popUpMenu(
|
||||
{ cName: "Ajouter de l'espace blanc autour du contenu", cReturn: "espace" },
|
||||
{ cName: "Deplacer le contenu (decalage)", cReturn: "deplacer" },
|
||||
{ cName: "Harmoniser les boites (Media/Crop/Bleed/Trim)", cReturn: "harmoniser" }
|
||||
);
|
||||
if (!action) { return; }
|
||||
|
||||
var portee = app.popUpMenu(
|
||||
{ cName: "Toutes les pages", cReturn: "toutes" },
|
||||
{ cName: "Page courante uniquement", cReturn: "courante" }
|
||||
);
|
||||
if (!portee) { return; }
|
||||
|
||||
var params;
|
||||
try {
|
||||
switch (action) {
|
||||
case "espace": {
|
||||
var haut = CDImp.Util.demanderNombre("Marge en haut (mm) :", "Ajouter de l'espace blanc", 0);
|
||||
if (haut === null) { return; }
|
||||
var bas = CDImp.Util.demanderNombre("Marge en bas (mm) :", "Ajouter de l'espace blanc", 0);
|
||||
if (bas === null) { return; }
|
||||
var gauche = CDImp.Util.demanderNombre("Marge a gauche (mm) :", "Ajouter de l'espace blanc", 0);
|
||||
if (gauche === null) { return; }
|
||||
var droite = CDImp.Util.demanderNombre("Marge a droite (mm) :", "Ajouter de l'espace blanc", 0);
|
||||
if (droite === null) { return; }
|
||||
params = { action: "espace", marges: { haut: haut, bas: bas, gauche: gauche, droite: droite }, portee: portee };
|
||||
CDImp.Marges.ajouterEspaceBlanc(doc, params.marges, portee);
|
||||
break;
|
||||
}
|
||||
case "deplacer": {
|
||||
var dx = CDImp.Util.demanderNombre("Decalage horizontal (mm, + = vers la droite) :", "Deplacer le contenu", 0);
|
||||
if (dx === null) { return; }
|
||||
var dy = CDImp.Util.demanderNombre("Decalage vertical (mm, + = vers le haut) :", "Deplacer le contenu", 0);
|
||||
if (dy === null) { return; }
|
||||
params = { action: "deplacer", dxMm: dx, dyMm: dy, portee: portee };
|
||||
var destDoc = CDImp.Marges.deplacerContenu(doc, dx, dy, portee);
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Marges.executer", params);
|
||||
}
|
||||
CDImp.Util.info("Contenu deplace dans un nouveau document.\nPensez a l'enregistrer (Ctrl+S) sous un nouveau nom.");
|
||||
return;
|
||||
}
|
||||
case "harmoniser": {
|
||||
var refBoite = app.popUpMenu(
|
||||
{ cName: "Aligner sur la TrimBox", cReturn: "Trim" },
|
||||
{ cName: "Aligner sur la CropBox", cReturn: "Crop" },
|
||||
{ cName: "Aligner sur la BleedBox", cReturn: "Bleed" },
|
||||
{ cName: "Aligner sur la MediaBox", cReturn: "Media" }
|
||||
);
|
||||
if (!refBoite) { return; }
|
||||
params = { action: "harmoniser", refBoite: refBoite, portee: portee };
|
||||
CDImp.Marges.harmoniserBoites(doc, refBoite, portee);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Marges.executer", params);
|
||||
}
|
||||
|
||||
CDImp.Util.info("Operation terminee avec succes.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Variante directe sans dialogues (Module 7 - Automatisation).
|
||||
*/
|
||||
CDImp.Marges.executerAvecParams = function (doc, params) {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
switch (params.action) {
|
||||
case "espace":
|
||||
CDImp.Marges.ajouterEspaceBlanc(doc, params.marges, params.portee);
|
||||
return doc;
|
||||
case "deplacer":
|
||||
return CDImp.Marges.deplacerContenu(doc, params.dxMm, params.dyMm, params.portee);
|
||||
case "harmoniser":
|
||||
CDImp.Marges.harmoniserBoites(doc, params.refBoite, params.portee);
|
||||
return doc;
|
||||
default:
|
||||
throw new Error("Action inconnue : " + params.action);
|
||||
}
|
||||
};
|
||||
242
acrobat-plugin/src/Imposition-06-Reperes.js
Executable file
242
acrobat-plugin/src/Imposition-06-Reperes.js
Executable file
@@ -0,0 +1,242 @@
|
||||
// Imposition-06-Reperes.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 6 : Reperes de coupe, textes et numerotation
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant).
|
||||
//
|
||||
// Les traits de coupe utilisent des annotations de type "Line" (API stable
|
||||
// et bien documentee : doc.addAnnot). La numerotation utilise
|
||||
// doc.addWatermarkFromText, egalement standard. Ces deux API sont plus
|
||||
// fiables que la technique template+CropBox utilisee dans les autres
|
||||
// modules, mais les constantes exactes de app.constants.align doivent etre
|
||||
// confirmees dans Acrobat Pro reel (non installe dans cet environnement de
|
||||
// developpement).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-06-Reperes.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Reperes = CDImp.Reperes || {};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Traits de coupe (8 reperes aux 4 coins, bases sur la TrimBox)
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Ajoute 8 traits de coupe (2 par coin) autour de la zone de delimitation
|
||||
* (TrimBox par defaut) de chaque page.
|
||||
*
|
||||
* @param {Doc} doc modifie en place
|
||||
* @param {Object} opts
|
||||
* decalageMm {Number} retrait entre le bord du format fini et le trait
|
||||
* longueurMm {Number} longueur de chaque trait
|
||||
* epaisseurPt {Number} epaisseur du trait en points
|
||||
* cBoxRef {String} boite de reference, "Trim" par defaut
|
||||
*/
|
||||
CDImp.Reperes.ajouterTraitsCoupe = function (doc, opts) {
|
||||
var decalage = CDImp.Util.mmToPt(opts.decalageMm);
|
||||
var longueur = CDImp.Util.mmToPt(opts.longueurMm);
|
||||
var epaisseur = opts.epaisseurPt || 0.25;
|
||||
var cBoxRef = opts.cBoxRef || "Trim";
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
for (var i = 0; i < doc.numPages; i++) {
|
||||
var box = doc.getPageBox({ nPage: i, cBox: cBoxRef });
|
||||
var llx = Math.min(box[0], box[2]);
|
||||
var lly = Math.min(box[1], box[3]);
|
||||
var urx = Math.max(box[0], box[2]);
|
||||
var ury = Math.max(box[1], box[3]);
|
||||
|
||||
var traits = [
|
||||
// bas-gauche
|
||||
[llx - decalage - longueur, lly, llx - decalage, lly],
|
||||
[llx, lly - decalage - longueur, llx, lly - decalage],
|
||||
// bas-droite
|
||||
[urx + decalage, lly, urx + decalage + longueur, lly],
|
||||
[urx, lly - decalage - longueur, urx, lly - decalage],
|
||||
// haut-gauche
|
||||
[llx - decalage - longueur, ury, llx - decalage, ury],
|
||||
[llx, ury + decalage, llx, ury + decalage + longueur],
|
||||
// haut-droite
|
||||
[urx + decalage, ury, urx + decalage + longueur, ury],
|
||||
[urx, ury + decalage, urx, ury + decalage + longueur]
|
||||
];
|
||||
|
||||
for (var t = 0; t < traits.length; t++) {
|
||||
var pts = traits[t];
|
||||
var rect = [
|
||||
Math.min(pts[0], pts[2]) - epaisseur, Math.min(pts[1], pts[3]) - epaisseur,
|
||||
Math.max(pts[0], pts[2]) + epaisseur, Math.max(pts[1], pts[3]) + epaisseur
|
||||
];
|
||||
doc.addAnnot({
|
||||
page: i,
|
||||
type: "Line",
|
||||
rect: rect,
|
||||
linePoints: pts,
|
||||
width: epaisseur,
|
||||
color: color.black,
|
||||
print: true,
|
||||
name: "CDImp_repere_" + i + "_" + t
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Numerotation sequentielle avancee
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* Remplace les variables dynamiques dans un modele de texte.
|
||||
* Variables : [Page], [Total], [NomDuFichier], [Date]
|
||||
*/
|
||||
CDImp.Reperes.remplacerVariables = function (modele, doc, numPage, total) {
|
||||
var date = util.printd("dd/mm/yyyy", new Date());
|
||||
return modele
|
||||
.replace(/\[Page\]/g, String(numPage))
|
||||
.replace(/\[Total\]/g, String(total))
|
||||
.replace(/\[NomDuFichier\]/g, doc.documentFileName || "")
|
||||
.replace(/\[Date\]/g, date);
|
||||
};
|
||||
|
||||
/**
|
||||
* Ajoute une numerotation / mention variable sur chaque page (sauf la
|
||||
* couverture si demande).
|
||||
*
|
||||
* @param {Doc} doc modifie en place
|
||||
* @param {Object} opts
|
||||
* modele {String} ex: "Page [Page] / [Total]"
|
||||
* police {String} ex: "Helvetica"
|
||||
* taillePt {Number}
|
||||
* positionXmm, positionYmm {Number} distance depuis le bord (selon coin)
|
||||
* coin {String} "bas_droite" | "bas_gauche" | "haut_droite" | "haut_gauche"
|
||||
* masquerPremierePage {Boolean}
|
||||
*/
|
||||
CDImp.Reperes.ajouterNumerotation = function (doc, opts) {
|
||||
var total = doc.numPages;
|
||||
var A = app.constants.align;
|
||||
var coins = {
|
||||
bas_droite: { h: A.right, v: A.bottom },
|
||||
bas_gauche: { h: A.left, v: A.bottom },
|
||||
haut_droite: { h: A.right, v: A.top },
|
||||
haut_gauche: { h: A.left, v: A.top }
|
||||
};
|
||||
var coin = coins[opts.coin] || coins.bas_droite;
|
||||
var offsetXPt = CDImp.Util.mmToPt(opts.positionXmm);
|
||||
var offsetYPt = CDImp.Util.mmToPt(opts.positionYmm);
|
||||
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
for (var i = 0; i < doc.numPages; i++) {
|
||||
var numPage = i + 1;
|
||||
if (opts.masquerPremierePage && numPage === 1) {
|
||||
continue;
|
||||
}
|
||||
var texte = CDImp.Reperes.remplacerVariables(opts.modele, doc, numPage, total);
|
||||
|
||||
doc.addWatermarkFromText({
|
||||
cText: texte,
|
||||
cFont: opts.police || "Helvetica",
|
||||
nFontSize: opts.taillePt || 9,
|
||||
nHorizAlign: coin.h,
|
||||
nVertAlign: coin.v,
|
||||
nHorizValue: offsetXPt,
|
||||
nVertValue: offsetYPt,
|
||||
nRotation: 0,
|
||||
nOpacity: 1.0,
|
||||
bOnTop: true,
|
||||
bOnscreen: true,
|
||||
bPrintable: true,
|
||||
nStart: i,
|
||||
nEnd: i
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree du module
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Reperes.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var action = app.popUpMenu(
|
||||
{ cName: "Ajouter les traits de coupe", cReturn: "traits" },
|
||||
{ cName: "Ajouter une numerotation / mention variable", cReturn: "numero" }
|
||||
);
|
||||
if (!action) { return; }
|
||||
|
||||
var params;
|
||||
try {
|
||||
if (action === "traits") {
|
||||
var decalageMm = CDImp.Util.demanderNombre("Retrait par rapport au format fini (mm) :", "Traits de coupe", 3);
|
||||
if (decalageMm === null) { return; }
|
||||
var longueurMm = CDImp.Util.demanderNombre("Longueur du trait (mm) :", "Traits de coupe", 5);
|
||||
if (longueurMm === null) { return; }
|
||||
params = { action: "traits", decalageMm: decalageMm, longueurMm: longueurMm, epaisseurPt: 0.25 };
|
||||
CDImp.Reperes.ajouterTraitsCoupe(doc, params);
|
||||
} else {
|
||||
var modele = app.response({ cQuestion: "Modele de texte ([Page], [Total], [NomDuFichier], [Date]) :", cTitle: "Numerotation", cDefault: "[Page] / [Total]" });
|
||||
if (modele === null) { return; }
|
||||
var taillePt = CDImp.Util.demanderNombre("Taille de police (pt) :", "Numerotation", 9);
|
||||
if (taillePt === null) { return; }
|
||||
var coin = app.popUpMenu(
|
||||
{ cName: "Bas droite", cReturn: "bas_droite" },
|
||||
{ cName: "Bas gauche", cReturn: "bas_gauche" },
|
||||
{ cName: "Haut droite", cReturn: "haut_droite" },
|
||||
{ cName: "Haut gauche", cReturn: "haut_gauche" }
|
||||
);
|
||||
if (!coin) { return; }
|
||||
var positionXmm = CDImp.Util.demanderNombre("Distance horizontale depuis le bord (mm) :", "Numerotation", 10);
|
||||
if (positionXmm === null) { return; }
|
||||
var positionYmm = CDImp.Util.demanderNombre("Distance verticale depuis le bord (mm) :", "Numerotation", 10);
|
||||
if (positionYmm === null) { return; }
|
||||
var masquerStr = app.popUpMenu(
|
||||
{ cName: "Afficher sur toutes les pages", cReturn: "non" },
|
||||
{ cName: "Masquer sur la premiere page (couverture)", cReturn: "oui" }
|
||||
);
|
||||
if (!masquerStr) { return; }
|
||||
|
||||
params = {
|
||||
action: "numero",
|
||||
modele: modele,
|
||||
police: "Helvetica",
|
||||
taillePt: taillePt,
|
||||
coin: coin,
|
||||
positionXmm: positionXmm,
|
||||
positionYmm: positionYmm,
|
||||
masquerPremierePage: masquerStr === "oui"
|
||||
};
|
||||
CDImp.Reperes.ajouterNumerotation(doc, params);
|
||||
}
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur : " + e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CDImp.Auto && CDImp.Auto.enregistrerDerniereAction) {
|
||||
CDImp.Auto.enregistrerDerniereAction("Reperes.executer", params);
|
||||
}
|
||||
|
||||
CDImp.Util.info("Operation terminee avec succes.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Variante directe sans dialogues (Module 7 - Automatisation).
|
||||
*/
|
||||
CDImp.Reperes.executerAvecParams = function (doc, params) {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
if (params.action === "traits") {
|
||||
CDImp.Reperes.ajouterTraitsCoupe(doc, params);
|
||||
} else if (params.action === "numero") {
|
||||
CDImp.Reperes.ajouterNumerotation(doc, params);
|
||||
} else {
|
||||
throw new Error("Action inconnue : " + params.action);
|
||||
}
|
||||
return doc;
|
||||
};
|
||||
189
acrobat-plugin/src/Imposition-07-Auto.js
Executable file
189
acrobat-plugin/src/Imposition-07-Auto.js
Executable file
@@ -0,0 +1,189 @@
|
||||
// Imposition-07-Auto.js
|
||||
// ---------------------------------------------------------------------------
|
||||
// Suite d'imposition professionnelle - Folder-Level Script pour Adobe Acrobat Pro
|
||||
// Module 7 : Automatisation (sequences de commandes / presets)
|
||||
//
|
||||
// Depend de Imposition-00-Core.js (doit etre charge avant) ainsi que des
|
||||
// modules 2 a 6 pour le rejeu d'actions (chacun expose une fonction
|
||||
// "executerAvecParams(doc, params)" sans dialogue, appelee ici).
|
||||
//
|
||||
// Les presets sont stockes dans l'objet global persistant
|
||||
// global.impositionSettings (survit aux fermetures d'Acrobat grace a
|
||||
// global.setPersistent). La "derniere action" n'est gardee qu'en memoire
|
||||
// pour la session courante.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (typeof CDImp === "undefined") {
|
||||
throw new Error("Imposition-07-Auto.js : CDImp.Core doit etre charge avant ce fichier.");
|
||||
}
|
||||
|
||||
CDImp.Auto = CDImp.Auto || {};
|
||||
|
||||
// Initialise l'espace de stockage persistant des presets.
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
if (typeof global.impositionSettings === "undefined") {
|
||||
global.impositionSettings = {};
|
||||
}
|
||||
global.setPersistent("impositionSettings", true);
|
||||
});
|
||||
|
||||
// Memoire de la derniere action executee (module + parametres), pour le
|
||||
// bouton "Repeter la derniere action". Reinitialisee a chaque session.
|
||||
CDImp.Auto.derniereAction = null;
|
||||
|
||||
// Table de correspondance "cle d'action" -> fonction de rejeu sans dialogue.
|
||||
// Chaque entree appelle la variante "executerAvecParams" du module concerne.
|
||||
CDImp.Auto._dispatch = {
|
||||
"Livret.imposer": function (doc, params) { return CDImp.Livret.executerAvecParams(doc, params); },
|
||||
"Livret.delivretiser": function (doc) { return CDImp.Livret.delivretiser(doc); },
|
||||
"NUp.executer": function (doc, params) { return CDImp.NUp.executerAvecParams(doc, params); },
|
||||
"Decoupe.executer": function (doc, params) { return CDImp.Decoupe.executerAvecParams(doc, params); },
|
||||
"Marges.executer": function (doc, params) { return CDImp.Marges.executerAvecParams(doc, params); },
|
||||
"Reperes.executer": function (doc, params) { return CDImp.Reperes.executerAvecParams(doc, params); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Appelee par chaque module a l'issue d'une execution reussie, pour
|
||||
* permettre "Repeter la derniere action" et la sauvegarde en preset.
|
||||
*
|
||||
* @param {String} cle une des cles de CDImp.Auto._dispatch
|
||||
* @param {Object} params parametres necessaires au rejeu
|
||||
*/
|
||||
CDImp.Auto.enregistrerDerniereAction = function (cle, params) {
|
||||
if (!CDImp.Auto._dispatch[cle]) {
|
||||
return; // cle inconnue : on ignore silencieusement (pas bloquant)
|
||||
}
|
||||
CDImp.Auto.derniereAction = { cle: cle, params: params || {} };
|
||||
};
|
||||
|
||||
/**
|
||||
* Rejoue la derniere action enregistree sur le document fourni (typiquement
|
||||
* un nouveau document different de celui d'origine), sans repasser par les
|
||||
* boites de dialogue.
|
||||
*/
|
||||
CDImp.Auto.repeterDerniereAction = function (doc) {
|
||||
if (!CDImp.Auto.derniereAction) {
|
||||
CDImp.Util.erreur("Aucune action a repeter : lancez d'abord un module d'imposition.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
var fn = CDImp.Auto._dispatch[CDImp.Auto.derniereAction.cle];
|
||||
var destDoc = fn(doc, CDImp.Auto.derniereAction.params);
|
||||
CDImp.Util.info("Derniere action (" + CDImp.Auto.derniereAction.cle + ") rejouee avec succes.");
|
||||
return destDoc;
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de la repetition de l'action : " + e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enregistre la derniere action sous un nom de preset persistant.
|
||||
*/
|
||||
CDImp.Auto.sauvegarderPreset = function (nomPreset) {
|
||||
if (!CDImp.Auto.derniereAction) {
|
||||
CDImp.Util.erreur("Aucune action a enregistrer : lancez d'abord un module d'imposition.");
|
||||
return;
|
||||
}
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
global.impositionSettings[nomPreset] = CDImp.Auto.derniereAction;
|
||||
});
|
||||
CDImp.Util.info("Preset \"" + nomPreset + "\" enregistre.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Retourne la liste des noms de presets enregistres.
|
||||
*/
|
||||
CDImp.Auto.listerPresets = function () {
|
||||
var noms = [];
|
||||
for (var nom in global.impositionSettings) {
|
||||
if (global.impositionSettings.hasOwnProperty(nom)) {
|
||||
noms.push(nom);
|
||||
}
|
||||
}
|
||||
return noms;
|
||||
};
|
||||
|
||||
/**
|
||||
* Charge un preset et l'execute directement sur le document fourni.
|
||||
*/
|
||||
CDImp.Auto.chargerEtExecuterPreset = function (doc, nomPreset) {
|
||||
var action = global.impositionSettings[nomPreset];
|
||||
if (!action) {
|
||||
CDImp.Util.erreur("Preset introuvable : " + nomPreset);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
var fn = CDImp.Auto._dispatch[action.cle];
|
||||
var destDoc = fn(doc, action.params);
|
||||
CDImp.Util.info("Preset \"" + nomPreset + "\" execute avec succes.");
|
||||
return destDoc;
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur("Erreur lors de l'execution du preset : " + e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Supprime un preset enregistre.
|
||||
*/
|
||||
CDImp.Auto.supprimerPreset = function (nomPreset) {
|
||||
CDImp.Util.avecPrivileges(function () {
|
||||
delete global.impositionSettings[nomPreset];
|
||||
});
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Point d'entree du module
|
||||
// -----------------------------------------------------------------------
|
||||
CDImp.Auto.lancer = function (doc) {
|
||||
try {
|
||||
doc = CDImp.Util.getDocActif(doc);
|
||||
} catch (e) {
|
||||
CDImp.Util.erreur(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
var presets = CDImp.Auto.listerPresets();
|
||||
var options = [
|
||||
{ cName: "Repeter la derniere action sur ce document", cReturn: "repeter" },
|
||||
{ cName: "Enregistrer la configuration actuelle comme preset", cReturn: "sauvegarder" }
|
||||
];
|
||||
if (presets.length > 0) {
|
||||
options.push({ cName: "Charger et executer un preset...", cReturn: "charger" });
|
||||
options.push({ cName: "Supprimer un preset...", cReturn: "supprimer" });
|
||||
}
|
||||
|
||||
var choix = app.popUpMenu.apply(app, options);
|
||||
if (!choix) { return; }
|
||||
|
||||
switch (choix) {
|
||||
case "repeter":
|
||||
CDImp.Auto.repeterDerniereAction(doc);
|
||||
break;
|
||||
|
||||
case "sauvegarder": {
|
||||
var nom = app.response({ cQuestion: "Nom du preset :", cTitle: "Enregistrer la configuration", cDefault: "MonPreset" });
|
||||
if (nom === null || nom === "") { return; }
|
||||
CDImp.Auto.sauvegarderPreset(nom);
|
||||
break;
|
||||
}
|
||||
|
||||
case "charger": {
|
||||
var presetsOptions = presets.map(function (n) { return { cName: n, cReturn: n }; });
|
||||
var nomChoisi = app.popUpMenu.apply(app, presetsOptions);
|
||||
if (!nomChoisi) { return; }
|
||||
CDImp.Auto.chargerEtExecuterPreset(doc, nomChoisi);
|
||||
break;
|
||||
}
|
||||
|
||||
case "supprimer": {
|
||||
var presetsOptionsSupp = presets.map(function (n) { return { cName: n, cReturn: n }; });
|
||||
var nomASupprimer = app.popUpMenu.apply(app, presetsOptionsSupp);
|
||||
if (!nomASupprimer) { return; }
|
||||
CDImp.Auto.supprimerPreset(nomASupprimer);
|
||||
CDImp.Util.info("Preset \"" + nomASupprimer + "\" supprime.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user