diff --git a/src/app/resource/controllers/ConvertThumbnailController.php b/src/app/resource/controllers/ConvertThumbnailController.php
new file mode 100644
index 0000000000000000000000000000000000000000..eb903e6410e2719df2c825552d20dc938ad57032
--- /dev/null
+++ b/src/app/resource/controllers/ConvertThumbnailController.php
@@ -0,0 +1,99 @@
+<?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 Convert Thumbnail Controller
+ * @author dev@maarch.org
+ * @ingroup core
+ */
+
+namespace Resource\controllers;
+
+
+use Attachment\models\AttachmentModel;
+use Docserver\controllers\DocserverController;
+use Docserver\models\DocserverModel;
+use Resource\models\AdrModel;
+use Resource\models\ResModel;
+use SrcCore\models\CoreConfigModel;
+use SrcCore\models\ValidatorModel;
+
+class ConvertThumbnailController
+{
+    public static function convert(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['collId', 'resId']);
+        ValidatorModel::stringType($aArgs, ['collId']);
+        ValidatorModel::intVal($aArgs, ['resId', 'outgoingId']);
+        ValidatorModel::boolType($aArgs, ['isOutgoingVersion']);
+
+
+        if ($aArgs['collId'] == 'letterbox_coll') {
+            if (empty($aArgs['outgoingId'])) {
+                $resource = ResModel::getById(['resId' => $aArgs['resId'], 'select' => ['docserver_id', 'path', 'filename']]);
+            } else {
+                $resource = AttachmentModel::getById(['id' => $aArgs['outgoingId'], 'isVersion' => $aArgs['isOutgoingVersion'], 'select' => ['docserver_id', 'path', 'filename']]);
+            }
+        }
+
+        if (empty($resource)) {
+            return ['errors' => '[ConvertThumbnail] Resource does not exist'];
+        }
+
+        $docserver = DocserverModel::getByDocserverId(['docserverId' => $resource['docserver_id'], 'select' => ['path_template']]);
+        if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+            return ['errors' => '[ConvertThumbnail] Docserver does not exist'];
+        }
+
+        $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $resource['path']) . $resource['filename'];
+        $ext = pathinfo($pathToDocument, PATHINFO_EXTENSION);
+        $tmpPath = CoreConfigModel::getTmpPath();
+        $fileNameOnTmp = rand() . basename($pathToDocument);
+
+        if (in_array($ext, ['maarch', 'html'])) {
+            if ($ext == 'maarch') {
+                copy($pathToDocument, "{$tmpPath}{$fileNameOnTmp}.html");
+                $pathToDocument = "{$tmpPath}{$fileNameOnTmp}.html";
+            }
+            $command = "wkhtmltoimage --height 600 --width 400 --quality 100 --zoom 0.2 "
+                . escapeshellarg($pathToDocument) . ' ' . escapeshellarg("{$tmpPath}{$fileNameOnTmp}.png");
+        } else {
+            $command = "convert -thumbnail 1000x1500 -background white -alpha remove "
+                . escapeshellarg($pathToDocument) . '[0] ' . escapeshellarg("{$tmpPath}{$fileNameOnTmp}.png");
+        }
+        exec($command, $output, $return);
+
+        if ($return !== 0) {
+            return ['errors' => "[ConvertThumbnail] {$output}"];
+        }
+
+        $storeResult = DocserverController::storeResourceOnDocServer([
+            'collId'    => $aArgs['collId'],
+            'fileInfos' => [
+                'tmpDir'        => $tmpPath,
+                'tmpFileName'   => $fileNameOnTmp . '.png',
+            ],
+            'docserverTypeId'   => 'TNL'
+        ]);
+
+        if (!empty($storeResult['errors'])) {
+            return ['errors' => "[ConvertThumbnail] {$storeResult['errors']}"];
+        }
+
+        AdrModel::createDocumentAdr([
+            'resId'         => $aArgs['resId'],
+            'type'          => 'TNL',
+            'docserverId'   => $storeResult['docserver_id'],
+            'path'          => $storeResult['destination_dir'],
+            'filename'      => $storeResult['file_destination_name'],
+        ]);
+
+        return true;
+    }
+}
diff --git a/src/app/resource/models/AdrModel.php b/src/app/resource/models/AdrModel.php
new file mode 100644
index 0000000000000000000000000000000000000000..0be5649631f559da95fd0a49d9d30f94eb196719
--- /dev/null
+++ b/src/app/resource/models/AdrModel.php
@@ -0,0 +1,95 @@
+<?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 Adr Model
+ * @author dev@maarch.org
+ */
+
+namespace Resource\models;
+
+use SrcCore\models\DatabaseModel;
+use SrcCore\models\ValidatorModel;
+
+class AdrModel
+{
+    public static function getDocumentsAdr(array $aArgs = [])
+    {
+        ValidatorModel::arrayType($aArgs, ['select', 'where', 'data', 'orderBy']);
+        ValidatorModel::intType($aArgs, ['limit', 'offset']);
+
+        $aReturn = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['adr_letterbox'],
+            'where'     => empty($aArgs['where']) ? [] : $aArgs['where'],
+            'data'      => empty($aArgs['data']) ? [] : $aArgs['data'],
+            'order_by'  => empty($aArgs['orderBy']) ? [] : $aArgs['orderBy'],
+            'offset'    => empty($aArgs['offset']) ? 0 : $aArgs['offset'],
+            'limit'     => empty($aArgs['limit']) ? 0 : $aArgs['limit']
+        ]);
+
+        return $aReturn;
+    }
+
+    public static function getTypedDocumentAdrByResId(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['resId', 'type']);
+        ValidatorModel::intVal($aArgs, ['resId']);
+        ValidatorModel::stringType($aArgs, ['type']);
+        ValidatorModel::arrayType($aArgs, ['select']);
+
+        $adr = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['adr_letterbox'],
+            'where'     => ['res_id = ?', 'type = ?'],
+            'data'      => [$aArgs['resId'], $aArgs['type']]
+        ]);
+
+        if (empty($adr[0])) {
+            return [];
+        }
+
+        return $adr[0];
+    }
+
+    public static function createDocumentAdr(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['resId', 'docserverId', 'path', 'filename', 'type']);
+        ValidatorModel::stringType($aArgs, ['docserverId', 'path', 'filename', 'type', 'fingerprint']);
+        ValidatorModel::intVal($aArgs, ['resId']);
+
+        DatabaseModel::insert([
+            'table'         => 'adr_letterbox',
+            'columnsValues' => [
+                'res_id'        => $aArgs['resId'],
+                'type'          => $aArgs['type'],
+                'docserver_id'  => $aArgs['docserverId'],
+                'path'          => $aArgs['path'],
+                'filename'      => $aArgs['filename'],
+                'fingerprint'   => empty($aArgs['fingerprint']) ? null : $aArgs['fingerprint'],
+            ]
+        ]);
+
+        return true;
+    }
+
+    public static function deleteDocumentAdr(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['where', 'data']);
+        ValidatorModel::arrayType($aArgs, ['where', 'data']);
+
+        DatabaseModel::delete([
+            'table' => 'adr_letterbox',
+            'where' => $aArgs['where'],
+            'data'  => $aArgs['data']
+        ]);
+
+        return true;
+    }
+}