diff --git a/apps/maarch_entreprise/indexing_searching/documents_list_mlb_search_adv.php b/apps/maarch_entreprise/indexing_searching/documents_list_mlb_search_adv.php
index ab3db7126496f48809af67180b4c2c79323cf8d9..f3e06acb6085e0fe691864d8ad04a9d8bad93237 100755
--- a/apps/maarch_entreprise/indexing_searching/documents_list_mlb_search_adv.php
+++ b/apps/maarch_entreprise/indexing_searching/documents_list_mlb_search_adv.php
@@ -676,9 +676,6 @@ if ($mode == 'normal') {
 
                 if ($tab[$i][$j][$value] == 'count_attachment') {
                     $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-                    if (!$core_tools->test_service('view_documents_with_notes', 'attachments', false)) {
-                        $excludeAttachmentTypes[] = 'document_with_notes';
-                    }
                     $query = "SELECT count(res_id) as total FROM res_attachments 
                             WHERE res_id_master = ? 
                             AND status NOT IN ('DEL', 'OBS') AND attachment_type NOT IN (?) AND (status <> 'TMP' or (typist = ? and status = 'TMP'))";
diff --git a/apps/maarch_entreprise/loadRepList.php b/apps/maarch_entreprise/loadRepList.php
index fb01c96df4df67dfd3c2a7f076ed363ca824f612..2d1bd63564977611458c8a641f683e9a307ee9ca 100755
--- a/apps/maarch_entreprise/loadRepList.php
+++ b/apps/maarch_entreprise/loadRepList.php
@@ -55,10 +55,6 @@ if (isset($_REQUEST['res_id_master'])) {
     $db = new Database();
 
     $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-    if (!$Core_Tools->test_service('view_documents_with_notes', 'attachments', false)) {
-        $excludeAttachmentTypes[] = 'document_with_notes';
-    }
-
     $query = "SELECT * FROM res_attachments 
                             WHERE res_id_master = ? 
                             AND status NOT IN ('DEL', 'OBS') AND attachment_type NOT IN (?)  AND (status <> 'TMP' or (typist = ? and status = 'TMP')) 
diff --git a/modules/attachments/frame_list_attachments.php b/modules/attachments/frame_list_attachments.php
index 77b84f9c08e53f20124df1d50256cb9cc5dc4c6b..c24b3dd7369d52ac0eafd8afee86807bf3bd28ad 100755
--- a/modules/attachments/frame_list_attachments.php
+++ b/modules/attachments/frame_list_attachments.php
@@ -102,10 +102,6 @@ array_push(
 
 $where = " (res_id_master = ? and status <> 'DEL' and status <> 'OBS' and (status <> 'TMP' or (typist = ? and status = 'TMP')))";
 
-if (!$core->test_service('view_documents_with_notes', 'attachments', false)) {
-    $where .= ' AND attachment_type <> \'document_with_notes\'';
-}
-
 $arrayPDO = array($resId, $_SESSION['user']['UserId']);
 //Filtre sur le type
 if (isset($whereAttach) && $whereAttach <> '') {
diff --git a/modules/attachments/load_toolbar_attachments.php b/modules/attachments/load_toolbar_attachments.php
index e58e275d76cf9fa4e914ab0714b80850dd589bfd..a0f965dcb039f2afce263317bb26112c314d8012 100755
--- a/modules/attachments/load_toolbar_attachments.php
+++ b/modules/attachments/load_toolbar_attachments.php
@@ -19,10 +19,6 @@ require_once 'core' . DIRECTORY_SEPARATOR . 'class' . DIRECTORY_SEPARATOR . 'cla
 $db = new Database;
 $core = new core_tools();
 
-if (!$core->test_service('view_documents_with_notes', 'attachments', false)) {
-    $exclude = ", 'document_with_notes'";
-}
-
 if ($_SESSION['req'] == 'details') {
     if (isset($_REQUEST['responses'])) {
         $stmt = $db->query("SELECT res_id, creation_date, title, format FROM "
diff --git a/rest/index.php b/rest/index.php
index 4fbadd82e329ad430029688a53e4dbae45e1d6f0..f8db28406b7169605150e6a82907d0921348998c 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -343,6 +343,7 @@ $app->post('/resources', \Resource\controllers\ResController::class . ':create')
 $app->get('/resources/{resId}', \Resource\controllers\ResController::class . ':getById');
 $app->put('/resources/{resId}', \Resource\controllers\ResController::class . ':update');
 $app->get('/resources/{resId}/content', \Resource\controllers\ResController::class . ':getFileContent');
+$app->get('/resources/{resId}/contents/{version}', \Resource\controllers\ResController::class . ':getFileContents');
 $app->get('/resources/{resId}/originalContent', \Resource\controllers\ResController::class . ':getOriginalFileContent');
 $app->get('/resources/{resId}/thumbnail', \Resource\controllers\ResController::class . ':getThumbnailContent');
 $app->get('/resources/{resId}/isAllowed', \Resource\controllers\ResController::class . ':isAllowedForCurrentUser');
diff --git a/src/app/attachment/controllers/AttachmentController.php b/src/app/attachment/controllers/AttachmentController.php
index 40df0df48fcff4eec2678092ab6d5a2a4c06e383..30de998baa66269e32792dc7d06568bc7d5cab8e 100755
--- a/src/app/attachment/controllers/AttachmentController.php
+++ b/src/app/attachment/controllers/AttachmentController.php
@@ -25,6 +25,7 @@ use Group\controllers\PrivilegeController;
 use History\controllers\HistoryController;
 use Resource\controllers\ResController;
 use Resource\controllers\StoreController;
+use Resource\controllers\WatermarkController;
 use Resource\models\ResModel;
 use Respect\Validation\Validator;
 use setasign\Fpdi\Tcpdf\Fpdi;
@@ -101,9 +102,6 @@ class AttachmentController
         }
 
         $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-        if (!PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
-            $excludeAttachmentTypes[] = 'document_with_notes';
-        }
         if (in_array($attachment['type'], $excludeAttachmentTypes)) {
             return $response->withStatus(400)->withJson(['errors' => 'Attachment type out of perimeter']);
         }
@@ -276,9 +274,6 @@ class AttachmentController
         }
 
         $excludeAttachmentTypes = ['converted_pdf', 'print_folder', 'signed_response'];
-        if (!PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
-            $excludeAttachmentTypes[] = 'document_with_notes';
-        }
 
         $attachments = AttachmentModel::get([
             'select'    => [
@@ -444,9 +439,7 @@ class AttachmentController
         $document = ConvertPdfController::getConvertedPdfById(['resId' => $attachment['res_id'], 'collId' => 'attachments_coll']);
         if (!empty($document['errors'])) {
             return $response->withStatus(400)->withJson(['errors' => 'Conversion error : ' . $document['errors']]);
-        }
-
-        if ($document['docserver_id'] == $attachment['docserver_id']) {
+        } elseif ($document['docserver_id'] == $attachment['docserver_id']) {
             return $response->withStatus(400)->withJson(['errors' => 'Document can not be converted']);
         }
 
@@ -456,7 +449,6 @@ class AttachmentController
         }
 
         $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $document['path']) . $document['filename'];
-
         if (!file_exists($pathToDocument)) {
             return $response->withStatus(404)->withJson(['errors' => 'Attachment not found on docserver']);
         }
@@ -467,71 +459,7 @@ class AttachmentController
             return $response->withStatus(400)->withJson(['errors' => 'Fingerprints do not match']);
         }
 
-        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'modules/attachments/xml/config.xml']);
-        if ($loadedXml) {
-            $watermark = (array)$loadedXml->CONFIG->watermark;
-            if ($watermark['enabled'] == 'true') {
-                $text = "watermark by {$GLOBALS['userId']}";
-                if (!empty($watermark['text'])) {
-                    $text = $watermark['text'];
-                    preg_match_all('/\[(.*?)\]/i', $watermark['text'], $matches);
-
-                    foreach ($matches[1] as $value) {
-                        $tmp = '';
-                        if ($value == 'date_now') {
-                            $tmp = date('d-m-Y');
-                        } elseif ($value == 'hour_now') {
-                            $tmp = date('H:i');
-                        } else {
-                            $backFromView = AttachmentModel::get(['select' => [$value], 'where' => ['res_id = ?'], 'data' => [$args['id']]]);
-                            if (!empty($backFromView[0][$value])) {
-                                $tmp = $backFromView[0][$value];
-                            }
-                        }
-                        $text = str_replace("[{$value}]", $tmp, $text);
-                    }
-                }
-
-                $color = ['192', '192', '192']; //RGB
-                if (!empty($watermark['text_color'])) {
-                    $rawColor = explode(',', $watermark['text_color']);
-                    $color = count($rawColor) == 3 ? $rawColor : $color;
-                }
-
-                $font = ['helvetica', '10']; //Familly Size
-                if (!empty($watermark['font'])) {
-                    $rawFont = explode(',', $watermark['font']);
-                    $font = count($rawFont) == 2 ? $rawFont : $font;
-                }
-
-                $position = [30, 35, 0, 0.5]; //X Y Angle Opacity
-                if (!empty($watermark['position'])) {
-                    $rawPosition = explode(',', $watermark['position']);
-                    $position = count($rawPosition) == 4 ? $rawPosition : $position;
-                }
-
-                try {
-                    $pdf = new Fpdi('P', 'pt');
-                    $nbPages = $pdf->setSourceFile($pathToDocument);
-                    $pdf->setPrintHeader(false);
-                    for ($i = 1; $i <= $nbPages; $i++) {
-                        $page = $pdf->importPage($i, 'CropBox');
-                        $size = $pdf->getTemplateSize($page);
-                        $pdf->AddPage($size['orientation'], $size);
-                        $pdf->useImportedPage($page);
-                        $pdf->SetFont($font[0], '', $font[1]);
-                        $pdf->SetTextColor($color[0], $color[1], $color[2]);
-                        $pdf->SetAlpha($position[3]);
-                        $pdf->Rotate($position[2]);
-                        $pdf->Text($position[0], $position[1], $text);
-                    }
-                    $fileContent = $pdf->Output('', 'S');
-                } catch (\Exception $e) {
-                    $fileContent = null;
-                }
-            }
-        }
-
+        $fileContent = WatermarkController::watermarkAttachment(['attachmentId' => $args['id'], 'path' => $pathToDocument]);
         if (empty($fileContent)) {
             $fileContent = file_get_contents($pathToDocument);
         }
diff --git a/src/app/folder/controllers/FolderController.php b/src/app/folder/controllers/FolderController.php
index a392590c31c6b69113cc36d76832b6a3223b936c..5dc38e13fb3a6d7a2df8bef888066cb02e2f4196 100755
--- a/src/app/folder/controllers/FolderController.php
+++ b/src/app/folder/controllers/FolderController.php
@@ -532,10 +532,6 @@ class FolderController
             $formattedResources = [];
             if (!empty($resIds)) {
                 $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-                if (!PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
-                    $excludeAttachmentTypes[] = 'document_with_notes';
-                }
-
                 $attachments = AttachmentModel::get([
                     'select'    => ['COUNT(res_id)', 'res_id_master'],
                     'where'     => ['res_id_master in (?)', 'status not in (?)', 'attachment_type not in (?)', '((status = ? AND typist = ?) OR status != ?)'],
diff --git a/src/app/resource/controllers/ResController.php b/src/app/resource/controllers/ResController.php
index 64aa6bacc0065987913651b34149e5113ddf6cbe..acd1cbbbcd525a516aea6f6fc6efd75b843e024a 100755
--- a/src/app/resource/controllers/ResController.php
+++ b/src/app/resource/controllers/ResController.php
@@ -45,7 +45,6 @@ use Resource\models\ResModel;
 use Resource\models\ResourceContactModel;
 use Resource\models\UserFollowedResourceModel;
 use Respect\Validation\Validator;
-use setasign\Fpdi\Tcpdf\Fpdi;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use SrcCore\controllers\PreparedClauseController;
@@ -376,18 +375,14 @@ class ResController
         $document = ResModel::getById(['select' => ['docserver_id', 'path', 'filename', 'fingerprint', 'category_id', 'alt_identifier'], 'resId' => $aArgs['resId']]);
         if (empty($document)) {
             return $response->withStatus(400)->withJson(['errors' => 'Document does not exist']);
-        }
-
-        if (empty($document['filename'])) {
+        } elseif (empty($document['filename'])) {
             return $response->withStatus(400)->withJson(['errors' => 'Document has no file']);
         }
 
         $convertedDocument = ConvertPdfController::getConvertedPdfById(['resId' => $aArgs['resId'], 'collId' => 'letterbox_coll']);
         if (!empty($convertedDocument['errors'])) {
             return $response->withStatus(400)->withJson(['errors' => 'Conversion error : ' . $convertedDocument['errors']]);
-        }
-
-        if ($document['docserver_id'] == $convertedDocument['docserver_id']) {
+        } elseif ($document['docserver_id'] == $convertedDocument['docserver_id']) {
             return $response->withStatus(400)->withJson(['errors' => 'Document can not be converted']);
         }
 
@@ -399,7 +394,6 @@ class ResController
         }
 
         $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $document['path']) . $document['filename'];
-
         if (!file_exists($pathToDocument)) {
             return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
         }
@@ -410,72 +404,7 @@ class ResController
             return $response->withStatus(400)->withJson(['errors' => 'Fingerprints do not match']);
         }
 
-        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'apps/maarch_entreprise/xml/features.xml']);
-        if ($loadedXml) {
-            $watermark = (array)$loadedXml->FEATURES->watermark;
-            if ($watermark['enabled'] == 'true') {
-                $text = "watermark by {$GLOBALS['userId']}";
-                if (!empty($watermark['text'])) {
-                    $text = $watermark['text'];
-                    preg_match_all('/\[(.*?)\]/i', $watermark['text'], $matches);
-
-                    foreach ($matches[1] as $value) {
-                        $tmp = '';
-                        if ($value == 'date_now') {
-                            $tmp = date('d-m-Y');
-                        } elseif ($value == 'hour_now') {
-                            $tmp = date('H:i');
-                        } elseif ($value == 'alt_identifier') {
-                            $tmp = $document['alt_identifier'];
-                        } else {
-                            $backFromView = ResModel::getOnView(['select' => $value, 'where' => ['res_id = ?'], 'data' => [$aArgs['resId']]]);
-                            if (!empty($backFromView[0][$value])) {
-                                $tmp = $backFromView[0][$value];
-                            }
-                        }
-                        $text = str_replace("[{$value}]", $tmp, $text);
-                    }
-                }
-
-                $color = ['192', '192', '192']; //RGB
-                if (!empty($watermark['text_color'])) {
-                    $rawColor = explode(',', $watermark['text_color']);
-                    $color = count($rawColor) == 3 ? $rawColor : $color;
-                }
-
-                $font = ['helvetica', '10']; //Familly Size
-                if (!empty($watermark['font'])) {
-                    $rawFont = explode(',', $watermark['font']);
-                    $font = count($rawFont) == 2 ? $rawFont : $font;
-                }
-
-                $position = [30, 35, 0, 0.5]; //X Y Angle Opacity
-                if (!empty($watermark['position'])) {
-                    $rawPosition = explode(',', $watermark['position']);
-                    $position = count($rawPosition) == 4 ? $rawPosition : $position;
-                }
-
-                try {
-                    $pdf = new Fpdi('P', 'pt');
-                    $nbPages = $pdf->setSourceFile($pathToDocument);
-                    $pdf->setPrintHeader(false);
-                    for ($i = 1; $i <= $nbPages; $i++) {
-                        $page = $pdf->importPage($i, 'CropBox');
-                        $size = $pdf->getTemplateSize($page);
-                        $pdf->AddPage($size['orientation'], $size);
-                        $pdf->useImportedPage($page);
-                        $pdf->SetFont($font[0], '', $font[1]);
-                        $pdf->SetTextColor($color[0], $color[1], $color[2]);
-                        $pdf->SetAlpha($position[3]);
-                        $pdf->Rotate($position[2]);
-                        $pdf->Text($position[0], $position[1], $text);
-                    }
-                    $fileContent = $pdf->Output('', 'S');
-                } catch (\Exception $e) {
-                    $fileContent = null;
-                }
-            }
-        }
+        $fileContent = WatermarkController::watermarkResource(['resId' => $aArgs['resId'], 'path' => $pathToDocument]);
 
         if (empty($fileContent)) {
             $fileContent = file_get_contents($pathToDocument);
@@ -484,11 +413,6 @@ class ResController
             return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
         }
 
-        ListInstanceModel::update([
-            'postSet'   => ['viewed' => 'viewed + 1'],
-            'where'     => ['item_id = ?', 'res_id = ?'],
-            'data'      => [$GLOBALS['userId'], $aArgs['resId']]
-        ]);
         HistoryController::add([
             'tableName' => 'res_letterbox',
             'recordId'  => $aArgs['resId'],
@@ -513,6 +437,61 @@ class ResController
         }
     }
 
+    public function getFileContents(Request $request, Response $response, array $args)
+    {
+        if (!Validator::intVal()->validate($args['resId']) || !ResController::hasRightByResId(['resId' => [$args['resId']], 'userId' => $GLOBALS['id']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+
+        $resource = ResModel::getById(['resId' => $args['resId'], 'select' => ['version', 'filename']]);
+        if (empty($resource['filename'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Document has no file']);
+        } elseif (!Validator::intVal()->validate($args['version']) || $args['version'] > $resource['version'] || $args['version'] < 1) {
+            return $response->withStatus(400)->withJson(['errors' => 'Incorrect version']);
+        }
+
+        $contents = [];
+        $convertedDocuments = AdrModel::getDocuments([
+            'select'    => ['docserver_id', 'path', 'filename', 'fingerprint', 'type'],
+            'where'     => ['res_id = ?', 'type in (?)', 'version = ?'],
+            'data'      => [$args['resId'], ['PDF', 'SIGN', 'NOTE'], $args['version']]
+        ]);
+
+        foreach ($convertedDocuments as $convertedDocument) {
+            $docserver = DocserverModel::getByDocserverId(['docserverId' => $convertedDocument['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]);
+            if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+                continue;
+            }
+
+            $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $convertedDocument['path']) . $convertedDocument['filename'];
+            if (!file_exists($pathToDocument)) {
+                continue;
+            }
+
+            $docserverType = DocserverTypeModel::getById(['id' => $docserver['docserver_type_id'], 'select' => ['fingerprint_mode']]);
+            $fingerprint = StoreController::getFingerPrint(['filePath' => $pathToDocument, 'mode' => $docserverType['fingerprint_mode']]);
+            if (!empty($document['fingerprint']) && $document['fingerprint'] != $fingerprint) {
+                return $response->withStatus(400)->withJson(['errors' => 'Fingerprints do not match']);
+            }
+
+            $fileContent = WatermarkController::watermarkResource(['resId' => $args['resId'], 'path' => $pathToDocument]);
+            if (empty($fileContent)) {
+                $fileContent = file_get_contents($pathToDocument);
+            }
+            if ($fileContent === false) {
+                continue;
+            }
+
+            if ($convertedDocument['type'] == 'NOTE' && !PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
+                continue;
+            }
+
+            $contents[$convertedDocument['type']] = base64_encode($fileContent);
+        }
+
+        return $response->withJson(['contents' => $contents]);
+    }
+
     public function getOriginalFileContent(Request $request, Response $response, array $aArgs)
     {
         if (!Validator::intVal()->validate($aArgs['resId']) || !ResController::hasRightByResId(['resId' => [$aArgs['resId']], 'userId' => $GLOBALS['id']])) {
@@ -544,9 +523,7 @@ class ResController
             return $response->withStatus(400)->withJson(['errors' => 'Fingerprints do not match']);
         }
 
-        if (empty($fileContent)) {
-            $fileContent = file_get_contents($pathToDocument);
-        }
+        $fileContent = file_get_contents($pathToDocument);
         if ($fileContent === false) {
             return $response->withStatus(404)->withJson(['errors' => 'Document not found on docserver']);
         }
@@ -558,11 +535,6 @@ class ResController
         $response->write($fileContent);
         $response = $response->withAddedHeader('Content-Disposition', "attachment; filename=maarch.{$pathInfo['extension']}");
 
-        ListInstanceModel::update([
-            'postSet'   => ['viewed' => 'viewed + 1'],
-            'where'     => ['item_id = ?', 'res_id = ?'],
-            'data'      => [$GLOBALS['userId'], $aArgs['resId']]
-        ]);
         HistoryController::add([
             'tableName' => 'res_letterbox',
             'recordId'  => $aArgs['resId'],
diff --git a/src/app/resource/controllers/ResourceListController.php b/src/app/resource/controllers/ResourceListController.php
index 6842d92494e27665d6279b1b1c445ab2b8cb4d7c..253b176aa3d7e8f22ba2369ec1089678bcea1066 100644
--- a/src/app/resource/controllers/ResourceListController.php
+++ b/src/app/resource/controllers/ResourceListController.php
@@ -89,10 +89,6 @@ class ResourceListController
         $displayFolderTags = false;
         if (!empty($resIds)) {
             $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-            if (!PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
-                $excludeAttachmentTypes[] = 'document_with_notes';
-            }
-
             $attachments = AttachmentModel::get([
                 'select'    => ['COUNT(res_id)', 'res_id_master'],
                 'where'     => ['res_id_master in (?)', 'status not in (?)', 'attachment_type not in (?)', '((status = ? AND typist = ?) OR status != ?)'],
diff --git a/src/app/resource/controllers/UserFollowedResourceController.php b/src/app/resource/controllers/UserFollowedResourceController.php
index 9c3b61a1b4ea39f2f58a312b9821f51fc70d4a53..696fa1f498d61ac158a87ddfc55eda8eec1ece34 100644
--- a/src/app/resource/controllers/UserFollowedResourceController.php
+++ b/src/app/resource/controllers/UserFollowedResourceController.php
@@ -116,10 +116,6 @@ class UserFollowedResourceController
             $formattedResources = [];
             if (!empty($resIds)) {
                 $excludeAttachmentTypes = ['converted_pdf', 'print_folder'];
-                if (!PrivilegeController::hasPrivilege(['privilegeId' => 'view_documents_with_notes', 'userId' => $GLOBALS['id']])) {
-                    $excludeAttachmentTypes[] = 'document_with_notes';
-                }
-
                 $attachments = AttachmentModel::get([
                     'select'    => ['COUNT(res_id)', 'res_id_master'],
                     'where'     => ['res_id_master in (?)', 'status not in (?)', 'attachment_type not in (?)', '((status = ? AND typist = ?) OR status != ?)'],
diff --git a/src/app/resource/controllers/WatermarkController.php b/src/app/resource/controllers/WatermarkController.php
new file mode 100644
index 0000000000000000000000000000000000000000..bf675ab5da9d16bf75159ccba60742a5d2b75136
--- /dev/null
+++ b/src/app/resource/controllers/WatermarkController.php
@@ -0,0 +1,170 @@
+<?php
+
+/**
+* Copyright Maarch since 2008 under licence GPLv3.
+* See LICENCE.txt file at the root folder for more details.
+* This file is part of Maarch software.
+*
+*/
+
+/**
+* @brief Watermark Controller
+* @author dev@maarch.org
+*/
+
+namespace Resource\controllers;
+
+use Attachment\models\AttachmentModel;
+use Resource\models\ResModel;
+use setasign\Fpdi\Tcpdf\Fpdi;
+use SrcCore\models\CoreConfigModel;
+use SrcCore\models\ValidatorModel;
+
+class WatermarkController
+{
+    public static function watermarkResource(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['resId', 'path']);
+        ValidatorModel::intVal($args, ['resId']);
+        ValidatorModel::stringType($args, ['path']);
+
+        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'apps/maarch_entreprise/xml/features.xml']);
+        if (empty($loadedXml)) {
+            return null;
+        }
+
+        $watermark = (array)$loadedXml->FEATURES->watermark;
+        if ($watermark['enabled'] != 'true') {
+            return null;
+        } elseif (empty($watermark['text'])) {
+            return null;
+        }
+
+        $text = $watermark['text'];
+        preg_match_all('/\[(.*?)\]/i', $watermark['text'], $matches);
+        foreach ($matches[1] as $value) {
+            if ($value == 'date_now') {
+                $tmp = date('d-m-Y');
+            } elseif ($value == 'hour_now') {
+                $tmp = date('H:i');
+            } else {
+                $resource = ResModel::getById(['select' => [$value], 'resId' => $args['resId']]);
+                $tmp = $resource[$value] ?? '';
+            }
+            $text = str_replace("[{$value}]", $tmp, $text);
+        }
+
+        $color = ['192', '192', '192']; //RGB
+        if (!empty($watermark['text_color'])) {
+            $rawColor = explode(',', $watermark['text_color']);
+            $color = count($rawColor) == 3 ? $rawColor : $color;
+        }
+
+        $font = ['helvetica', '10']; //Familly Size
+        if (!empty($watermark['font'])) {
+            $rawFont = explode(',', $watermark['font']);
+            $font = count($rawFont) == 2 ? $rawFont : $font;
+        }
+
+        $position = [30, 35, 0, 0.5]; //X Y Angle Opacity
+        if (!empty($watermark['position'])) {
+            $rawPosition = explode(',', $watermark['position']);
+            $position = count($rawPosition) == 4 ? $rawPosition : $position;
+        }
+
+        try {
+            $pdf = new Fpdi('P', 'pt');
+            $nbPages = $pdf->setSourceFile($args['path']);
+            $pdf->setPrintHeader(false);
+            for ($i = 1; $i <= $nbPages; $i++) {
+                $page = $pdf->importPage($i, 'CropBox');
+                $size = $pdf->getTemplateSize($page);
+                $pdf->AddPage($size['orientation'], $size);
+                $pdf->useImportedPage($page);
+                $pdf->SetFont($font[0], '', $font[1]);
+                $pdf->SetTextColor($color[0], $color[1], $color[2]);
+                $pdf->SetAlpha($position[3]);
+                $pdf->Rotate($position[2]);
+                $pdf->Text($position[0], $position[1], $text);
+            }
+            $fileContent = $pdf->Output('', 'S');
+        } catch (\Exception $e) {
+            $fileContent = null;
+        }
+
+        return $fileContent;
+    }
+
+    public static function watermarkAttachment(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['attachmentId', 'path']);
+        ValidatorModel::intVal($args, ['attachmentId']);
+        ValidatorModel::stringType($args, ['path']);
+
+        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'modules/attachments/xml/config.xml']);
+        if (empty($loadedXml)) {
+            return null;
+        }
+
+        $watermark = (array)$loadedXml->CONFIG->watermark;
+        if ($watermark['enabled'] != 'true') {
+            return null;
+        } elseif (empty($watermark['text'])) {
+            return null;
+        }
+
+        $text = $watermark['text'];
+        preg_match_all('/\[(.*?)\]/i', $watermark['text'], $matches);
+        foreach ($matches[1] as $value) {
+            if ($value == 'date_now') {
+                $tmp = date('d-m-Y');
+            } elseif ($value == 'hour_now') {
+                $tmp = date('H:i');
+            } else {
+                $attachment = AttachmentModel::getById(['select' => [$value], 'id' => $args['attachmentId']]);
+                $tmp = $attachment[$value] ?? '';
+            }
+            $text = str_replace("[{$value}]", $tmp, $text);
+        }
+
+        $color = ['192', '192', '192']; //RGB
+        if (!empty($watermark['text_color'])) {
+            $rawColor = explode(',', $watermark['text_color']);
+            $color = count($rawColor) == 3 ? $rawColor : $color;
+        }
+
+        $font = ['helvetica', '10']; //Familly Size
+        if (!empty($watermark['font'])) {
+            $rawFont = explode(',', $watermark['font']);
+            $font = count($rawFont) == 2 ? $rawFont : $font;
+        }
+
+        $position = [30, 35, 0, 0.5]; //X Y Angle Opacity
+        if (!empty($watermark['position'])) {
+            $rawPosition = explode(',', $watermark['position']);
+            $position = count($rawPosition) == 4 ? $rawPosition : $position;
+        }
+
+        try {
+            $pdf = new Fpdi('P', 'pt');
+            $nbPages = $pdf->setSourceFile($args['path']);
+            $pdf->setPrintHeader(false);
+            for ($i = 1; $i <= $nbPages; $i++) {
+                $page = $pdf->importPage($i, 'CropBox');
+                $size = $pdf->getTemplateSize($page);
+                $pdf->AddPage($size['orientation'], $size);
+                $pdf->useImportedPage($page);
+                $pdf->SetFont($font[0], '', $font[1]);
+                $pdf->SetTextColor($color[0], $color[1], $color[2]);
+                $pdf->SetAlpha($position[3]);
+                $pdf->Rotate($position[2]);
+                $pdf->Text($position[0], $position[1], $text);
+            }
+            $fileContent = $pdf->Output('', 'S');
+        } catch (\Exception $e) {
+            $fileContent = null;
+        }
+
+        return $fileContent;
+    }
+}