mirror of
https://github.com/24eme/signaturepdf
synced 2026-03-14 13:55:44 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
e54e83e896
9 changed files with 356 additions and 37 deletions
7
app.php
7
app.php
|
|
@ -174,7 +174,7 @@ $f3->route('POST /image2svg',
|
|||
|
||||
shell_exec(sprintf("convert -background white -flatten %s %s", $imageFile, $imageFile.".bmp"));
|
||||
shell_exec(sprintf("mkbitmap -x -f 8 %s -o %s", $imageFile.".bmp", $imageFile.".bpm"));
|
||||
shell_exec(sprintf("potrace --svg %s -o %s", $imageFile.".bpm", $imageFile.".svg"));
|
||||
shell_exec(sprintf("potrace --flat --svg %s -o %s", $imageFile.".bpm", $imageFile.".svg"));
|
||||
|
||||
header('Content-Type: image/svg+xml');
|
||||
echo file_get_contents($imageFile.".svg");
|
||||
|
|
@ -189,7 +189,6 @@ $f3->route('POST /image2svg',
|
|||
$f3->route('POST /sign',
|
||||
function($f3) {
|
||||
$filename = null;
|
||||
$filigrane = $f3->get('POST.watermark');
|
||||
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_sign_'.uniqid("", true));
|
||||
unlink($tmpfile);
|
||||
$svgFiles = [];
|
||||
|
|
@ -227,8 +226,8 @@ $f3->route('POST /sign',
|
|||
|
||||
PDFSignature::createPDFFromSvg($svgFiles, $tmpfile.'.svg.pdf');
|
||||
PDFSignature::addSvgToPDF($tmpfile.'.pdf', $tmpfile.'.svg.pdf', $tmpfile.'_signe.pdf');
|
||||
if ($filigrane) {
|
||||
PDFSignature::addFiligrane($filigrane, $tmpfile);
|
||||
if ($f3->get('POST.flatten')) {
|
||||
PDFSignature::flatten($tmpfile);
|
||||
}
|
||||
|
||||
Web::instance()->send($tmpfile.'_signe.pdf', null, 0, TRUE, $filename);
|
||||
|
|
|
|||
|
|
@ -196,26 +196,14 @@ class PDFSignature
|
|||
}
|
||||
}
|
||||
|
||||
public static function addFiligrane($text, $pdf)
|
||||
public static function flatten($pdf)
|
||||
{
|
||||
// check version of imagick
|
||||
$command = (null === shell_exec("command -v magick")) ? 'convert' : 'magick';
|
||||
|
||||
// Création texte watermark
|
||||
$watermarkCommand = sprintf(
|
||||
'%s -density 144 -units PixelsPerInch pdf:%s_signe.pdf -write mpr:base \
|
||||
\( -density 144 -units PixelsPerInch -background None -fill "#0007" -pointsize 20 label:%s -rotate -40 +repage -write mpr:TILE +delete \) \
|
||||
\( -clone 0 -tile mpr:TILE -draw "color 0,0 reset" -write mpr:TILES -delete 0 \) \
|
||||
-delete 0--1 \
|
||||
mpr:TILES null: mpr:base \
|
||||
-compose Overlay -layers composite \
|
||||
-density 144 -units PixelsPerInch \
|
||||
-sharpen 0x1.0 \
|
||||
-compress zip \
|
||||
pdf:%s_signe.pdf'
|
||||
, $command, escapeshellarg($pdf), escapeshellarg($text), escapeshellarg($pdf));
|
||||
|
||||
shell_exec($watermarkCommand);
|
||||
shell_exec(sprintf(
|
||||
'%s -density 200 -units PixelsPerInch %s_signe.pdf -compress zip %s_signe.pdf'
|
||||
, $command, escapeshellarg($pdf), escapeshellarg($pdf)));
|
||||
}
|
||||
|
||||
public function clean() {
|
||||
|
|
|
|||
120
public/css/pdf_viewer.css
Normal file
120
public/css/pdf_viewer.css
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
.textLayer{
|
||||
position:absolute;
|
||||
text-align:initial;
|
||||
inset:0;
|
||||
overflow:clip;
|
||||
opacity:1;
|
||||
line-height:1;
|
||||
-webkit-text-size-adjust:none;
|
||||
-moz-text-size-adjust:none;
|
||||
text-size-adjust:none;
|
||||
forced-color-adjust:none;
|
||||
transform-origin:0 0;
|
||||
caret-color:CanvasText;
|
||||
z-index:0;
|
||||
}
|
||||
|
||||
.textLayer.highlighting{
|
||||
touch-action:none;
|
||||
}
|
||||
|
||||
.textLayer :is(span,br){
|
||||
color:transparent;
|
||||
position:absolute;
|
||||
white-space:pre;
|
||||
cursor:text;
|
||||
transform-origin:0% 0%;
|
||||
}
|
||||
|
||||
.textLayer > :not(.markedContent),.textLayer .markedContent span:not(.markedContent){
|
||||
z-index:1;
|
||||
}
|
||||
|
||||
.textLayer span.markedContent{
|
||||
top:0;
|
||||
height:0;
|
||||
}
|
||||
|
||||
.textLayer .highlight{
|
||||
--highlight-bg-color:rgb(180 0 170 / 0.25);
|
||||
--highlight-selected-bg-color:rgb(0 100 0 / 0.25);
|
||||
--highlight-backdrop-filter:none;
|
||||
--highlight-selected-backdrop-filter:none;
|
||||
}
|
||||
|
||||
@media screen and (forced-colors: active){
|
||||
|
||||
.textLayer .highlight{
|
||||
--highlight-bg-color:transparent;
|
||||
--highlight-selected-bg-color:transparent;
|
||||
--highlight-backdrop-filter:var(--hcm-highlight-filter);
|
||||
--highlight-selected-backdrop-filter:var(
|
||||
--hcm-highlight-selected-filter
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.textLayer .highlight{
|
||||
|
||||
margin:-1px;
|
||||
padding:1px;
|
||||
background-color:var(--highlight-bg-color);
|
||||
-webkit-backdrop-filter:var(--highlight-backdrop-filter);
|
||||
backdrop-filter:var(--highlight-backdrop-filter);
|
||||
border-radius:4px;
|
||||
}
|
||||
|
||||
.appended:is(.textLayer .highlight){
|
||||
position:initial;
|
||||
}
|
||||
|
||||
.begin:is(.textLayer .highlight){
|
||||
border-radius:4px 0 0 4px;
|
||||
}
|
||||
|
||||
.end:is(.textLayer .highlight){
|
||||
border-radius:0 4px 4px 0;
|
||||
}
|
||||
|
||||
.middle:is(.textLayer .highlight){
|
||||
border-radius:0;
|
||||
}
|
||||
|
||||
.selected:is(.textLayer .highlight){
|
||||
background-color:var(--highlight-selected-bg-color);
|
||||
-webkit-backdrop-filter:var(--highlight-selected-backdrop-filter);
|
||||
backdrop-filter:var(--highlight-selected-backdrop-filter);
|
||||
}
|
||||
|
||||
.textLayer ::-moz-selection{
|
||||
background:rgba(0 0 255 / 0.25);
|
||||
background:color-mix(in srgb, AccentColor, transparent 75%);
|
||||
}
|
||||
|
||||
.textLayer ::selection{
|
||||
background:rgba(0 0 255 / 0.25);
|
||||
background:color-mix(in srgb, AccentColor, transparent 75%);
|
||||
}
|
||||
|
||||
.textLayer br::-moz-selection{
|
||||
background:transparent;
|
||||
}
|
||||
|
||||
.textLayer br::selection{
|
||||
background:transparent;
|
||||
}
|
||||
|
||||
.textLayer .endOfContent{
|
||||
display:block;
|
||||
position:absolute;
|
||||
inset:100% 0 0;
|
||||
z-index:0;
|
||||
cursor:default;
|
||||
-webkit-user-select:none;
|
||||
-moz-user-select:none;
|
||||
user-select:none;
|
||||
}
|
||||
|
||||
.textLayer.selecting .endOfContent{
|
||||
top:0;
|
||||
}
|
||||
|
|
@ -259,3 +259,15 @@ async function imageToPdf(file) {
|
|||
function convertOctet2MegoOctet(nbOctet) {
|
||||
return (Math.round(nbOctet/1000/1000*100)/100).toFixed(2);
|
||||
}
|
||||
|
||||
function debounce(callback, delay){
|
||||
let timer;
|
||||
return function(){
|
||||
const args = arguments;
|
||||
const context = this;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function(){
|
||||
callback.apply(context, args);
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,14 +81,34 @@ async function pageRender(pageIndex) {
|
|||
let scaleWidth = sizeWidth / viewport.width;
|
||||
let viewportWidth = page.getViewport({scale: scaleWidth });
|
||||
|
||||
document.documentElement.style.setProperty('--scale-factor', scaleWidth) // needed to scale the textLayer
|
||||
// to the canvas size (var used in style attribute)
|
||||
|
||||
viewport = viewportWidth;
|
||||
|
||||
let canvasPDF = document.createElement('canvas');
|
||||
canvasPDF.classList.add('shadow-sm');
|
||||
document.getElementById('container-pages').appendChild(canvasPDF);
|
||||
let context = canvasPDF.getContext('2d');
|
||||
const containerPagePDF = document.createElement('div')
|
||||
const canvasPDF = document.createElement('canvas')
|
||||
const wrapperPDF = document.createElement('div')
|
||||
const textPDF = document.createElement('div')
|
||||
|
||||
document.getElementById('container-pages').appendChild(containerPagePDF)
|
||||
containerPagePDF.appendChild(wrapperPDF)
|
||||
wrapperPDF.appendChild(canvasPDF)
|
||||
wrapperPDF.appendChild(textPDF)
|
||||
|
||||
const context = canvasPDF.getContext('2d')
|
||||
|
||||
canvasPDF.height = viewport.height;
|
||||
canvasPDF.width = viewport.width;
|
||||
canvasPDF.classList.add('shadow-sm');
|
||||
|
||||
containerPagePDF.classList.add('page')
|
||||
containerPagePDF.setAttribute('id', 'container-page-'+pageIndex)
|
||||
|
||||
wrapperPDF.classList.add('canvasWrapper');
|
||||
wrapperPDF.style.position = 'relative'
|
||||
|
||||
textPDF.classList.add('textLayer')
|
||||
|
||||
if(pdfRenderTasks[pageIndex]) {
|
||||
pdfRenderTasks[pageIndex].cancel();
|
||||
|
|
@ -97,6 +117,18 @@ async function pageRender(pageIndex) {
|
|||
canvasContext: context,
|
||||
viewport: viewport,
|
||||
});
|
||||
|
||||
pdfRenderTasks[pageIndex].promise.then(function () {
|
||||
return page.getTextContent()
|
||||
}).then(function (textContent) {
|
||||
const textLayer = new pdfjsLib.TextLayer({
|
||||
textContentSource: textContent,
|
||||
viewport: viewport,
|
||||
container: textPDF,
|
||||
});
|
||||
|
||||
textLayer.render()
|
||||
})
|
||||
}
|
||||
|
||||
function addMetadata(key, value, type, focus) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ let menu = null;
|
|||
let menuOffcanvas = null;
|
||||
let currentCursor = null;
|
||||
let signaturePad = null;
|
||||
const penColorPicker = document.getElementById('penColorPicker');
|
||||
let penColor = localStorage.getItem('penColor') ?? '#000000'
|
||||
let nblayers = null;
|
||||
let hasModifications = false;
|
||||
let currentTextScale = 1;
|
||||
|
|
@ -131,6 +133,9 @@ async function loadPDF(pdfBlob) {
|
|||
if (event.target instanceof fabric.Line) {
|
||||
return;
|
||||
}
|
||||
if (event.target instanceof fabric.Rect) {
|
||||
return;
|
||||
}
|
||||
if(event.transform.action == "scaleX") {
|
||||
event.target.scaleY = event.target.scaleX;
|
||||
}
|
||||
|
|
@ -157,6 +162,13 @@ async function loadPDF(pdfBlob) {
|
|||
const textLinesMaxWidth = event.target.textLines.reduce((max, _, i) => Math.max(max, event.target.getLineWidth(i)), 0);
|
||||
event.target.set({width: textLinesMaxWidth});
|
||||
});
|
||||
canvasEdition.on("selection:created", function(event) {
|
||||
if (event.selected.length > 1 || event.selected.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
toolBox.init(event.selected[0])
|
||||
});
|
||||
canvasEditions.push(canvasEdition);
|
||||
});
|
||||
}
|
||||
|
|
@ -264,7 +276,7 @@ function svgChange(input, event) {
|
|||
|
||||
let input_selected = document.querySelector('input[name="svg_2_add"]:checked');
|
||||
|
||||
if(input_selected && !input_selected.value.match(/^data:/) && input_selected.value != "text" && input_selected.value != "strikethrough") {
|
||||
if(input_selected && !input_selected.value.match(/^data:/) && input_selected.value != "text" && input_selected.value != "strikethrough" && input_selected.value != "rectangle") {
|
||||
input_selected = null;
|
||||
}
|
||||
|
||||
|
|
@ -430,6 +442,9 @@ function deleteActiveObject() {
|
|||
canvasEditions.forEach(function(canvasEdition, index) {
|
||||
canvasEdition.getActiveObjects().forEach(function(activeObject) {
|
||||
canvasEdition.remove(activeObject);
|
||||
if(activeObject.type == "rect") {
|
||||
updateFlatten();
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
|
|
@ -459,6 +474,42 @@ function addObjectInCanvas(canvas, item) {
|
|||
return canvas.add(item);
|
||||
};
|
||||
|
||||
function updateWatermark() {
|
||||
const text = new fabric.Text(document.querySelector('input[name=watermark]').value, {angle: -40, fill: "#0009", fontSize: 27 * currentScale})
|
||||
text.scale = 0.
|
||||
const overlay = new fabric.Rect({
|
||||
fill: new fabric.Pattern({
|
||||
source: text.toCanvasElement(),
|
||||
}),
|
||||
})
|
||||
|
||||
canvasEditions.forEach(function (canvas) {
|
||||
overlay.height = canvas.height
|
||||
overlay.width = canvas.width
|
||||
|
||||
canvas.objectCaching = false
|
||||
canvas.setOverlayImage(overlay, canvas.renderAll.bind(canvas), {
|
||||
objectCaching: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function updateFlatten() {
|
||||
let flatten = Boolean(document.querySelector('input[name=watermark]').value);
|
||||
|
||||
flatten = flatten || canvasEditions.some(function (canvas) {
|
||||
return canvas.getObjects().some(function (object) {
|
||||
return object.type === "rect"
|
||||
})
|
||||
})
|
||||
|
||||
document.querySelector('input[name=flatten]').checked = flatten;
|
||||
if(document.getElementById('save_flatten_indicator')) {
|
||||
document.getElementById('save_flatten_indicator').classList.toggle('invisible', !flatten);
|
||||
}
|
||||
}
|
||||
|
||||
function setIsChanged(changed) {
|
||||
hasModifications = changed
|
||||
|
||||
|
|
@ -494,7 +545,8 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
top: y - 20,
|
||||
fontSize: 20,
|
||||
direction: direction,
|
||||
fontFamily: 'Monospace'
|
||||
fontFamily: 'Monospace',
|
||||
fill: penColor
|
||||
});
|
||||
|
||||
addObjectInCanvas(canvas, textbox).setActiveObject(textbox);
|
||||
|
|
@ -511,8 +563,8 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
|
||||
if(item == 'strikethrough') {
|
||||
let line = new fabric.Line([x, y, x + 250, y], {
|
||||
fill: 'black',
|
||||
stroke: 'black',
|
||||
fill: penColor,
|
||||
stroke: penColor,
|
||||
lockScalingFlip: true,
|
||||
strokeWidth: 2,
|
||||
padding: 10,
|
||||
|
|
@ -524,6 +576,23 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(item == 'rectangle') {
|
||||
let rect = new fabric.Rect({
|
||||
left: x,
|
||||
top: y,
|
||||
width: 200,
|
||||
height: 100,
|
||||
fill: '#000',
|
||||
lockScalingFlip: true
|
||||
});
|
||||
rect.setControlsVisibility({ tl: false, tr: false, bl: false, br: false,})
|
||||
|
||||
addObjectInCanvas(canvas, rect).setActiveObject(rect);
|
||||
|
||||
updateFlatten();
|
||||
return;
|
||||
}
|
||||
|
||||
fabric.loadSVGFromURL(item, function(objects, options) {
|
||||
let svg = fabric.util.groupSVGElements(objects, options);
|
||||
svg.svgOrigin = item;
|
||||
|
|
@ -539,6 +608,8 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
svg.top = y - (svg.getScaledHeight() / 2);
|
||||
svg.left = x - (svg.getScaledWidth() / 2);
|
||||
|
||||
svg.fill = penColor
|
||||
|
||||
addObjectInCanvas(canvas, svg);
|
||||
});
|
||||
};
|
||||
|
|
@ -546,6 +617,7 @@ function createAndAddSvgInCanvas(canvas, item, x, y, height = null) {
|
|||
function autoZoom() {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(resizePDF, 100);
|
||||
updateWatermark();
|
||||
};
|
||||
|
||||
function zoomChange(inOrOut) {
|
||||
|
|
@ -631,6 +703,8 @@ function resizePDF(scale = 'auto') {
|
|||
resizeTimeout = null;
|
||||
});
|
||||
});
|
||||
|
||||
updateWatermark();
|
||||
};
|
||||
|
||||
function createEventsListener() {
|
||||
|
|
@ -765,9 +839,31 @@ function createEventsListener() {
|
|||
div.classList.add('d-none')
|
||||
input.querySelector('input').focus()
|
||||
})
|
||||
document.querySelector('input[name=watermark]')?.addEventListener('keyup', function (e) {
|
||||
|
||||
document.querySelector('input[name=watermark]')?.addEventListener('keyup', debounce(function (e) {
|
||||
setIsChanged(hasModifications || !!e.target.value)
|
||||
})
|
||||
updateFlatten();
|
||||
|
||||
// Pourquoi 27 : 40 / 1.5 = 26.6666
|
||||
// fontSize ^ ^ currentScale par défaut
|
||||
// Comme ça le texte de l'overlay ne bouge pas au zoom
|
||||
const text = new fabric.Text(e.target.value, {angle: -40, fill: "#0009", fontSize: 27 * currentScale})
|
||||
const overlay = new fabric.Rect({
|
||||
fill: new fabric.Pattern({
|
||||
source: text.toCanvasElement(),
|
||||
}),
|
||||
})
|
||||
|
||||
canvasEditions.forEach(function (canvas) {
|
||||
overlay.height = canvas.height
|
||||
overlay.width = canvas.width
|
||||
|
||||
canvas.objectCaching = false
|
||||
canvas.setOverlayImage(overlay, canvas.renderAll.bind(canvas), {
|
||||
objectCaching: false
|
||||
})
|
||||
})
|
||||
}, 750))
|
||||
|
||||
if(document.querySelector('#alert-signature-help')) {
|
||||
document.getElementById('btn-signature-help').addEventListener('click', function(event) {
|
||||
|
|
@ -931,6 +1027,11 @@ function createEventsListener() {
|
|||
zoomChange(1)
|
||||
});
|
||||
|
||||
penColorPicker.addEventListener('input', function (e) {
|
||||
e.preventDefault()
|
||||
storePenColor(penColorPicker.value)
|
||||
})
|
||||
|
||||
window.addEventListener('beforeunload', function(event) {
|
||||
if(!hasModifications) {
|
||||
return;
|
||||
|
|
@ -954,14 +1055,14 @@ function createSignaturePad() {
|
|||
minWidth: 1,
|
||||
maxWidth: 2
|
||||
});
|
||||
signaturePad.addEventListener('endStroke', function(){
|
||||
signaturePad.addEventListener('endStroke', debounce(function(){
|
||||
const file = new File([dataURLtoBlob(signaturePad.toDataURL())], "draw.png", {
|
||||
type: 'image/png'
|
||||
});
|
||||
let data = new FormData();
|
||||
data.append('file', file);
|
||||
uploadSVG(data);
|
||||
});
|
||||
}, 500));
|
||||
};
|
||||
|
||||
async function getPDFBlobFromCache(cacheUrl) {
|
||||
|
|
@ -1086,6 +1187,7 @@ async function pageSignature(url) {
|
|||
return;
|
||||
}
|
||||
|
||||
storePenColor(penColor)
|
||||
createSignaturePad();
|
||||
responsiveDisplay();
|
||||
displaysSVG();
|
||||
|
|
@ -1118,3 +1220,62 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||
window.location.reload();
|
||||
})
|
||||
});
|
||||
|
||||
function storePenColor(color) {
|
||||
penColor = color
|
||||
penColorPicker.value = color
|
||||
localStorage.setItem('penColor', penColor)
|
||||
}
|
||||
|
||||
const toolBox = (function () {
|
||||
const _coloricon = document.createElement('img')
|
||||
_coloricon.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-palette" viewBox="0 0 16 16"><path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3m4 3a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M5.5 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m.5 6a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3"/><path d="M16 8c0 3.15-1.866 2.585-3.567 2.07C11.42 9.763 10.465 9.473 10 10c-.603.683-.475 1.819-.351 2.92C9.826 14.495 9.996 16 8 16a8 8 0 1 1 8-8m-8 7c.611 0 .654-.171.655-.176.078-.146.124-.464.07-1.119-.014-.168-.037-.37-.061-.591-.052-.464-.112-1.005-.118-1.462-.01-.707.083-1.61.704-2.314.369-.417.845-.578 1.272-.618.404-.038.812.026 1.16.104.343.077.702.186 1.025.284l.028.008c.346.105.658.199.953.266.653.148.904.083.991.024C14.717 9.38 15 9.161 15 8a7 7 0 1 0-7 7"/></svg>'
|
||||
|
||||
function _renderIcon(icon) {
|
||||
return function renderIcon(ctx, left, top, styleOverride, fabricObject) {
|
||||
const size = this.cornerSize;
|
||||
ctx.save();
|
||||
ctx.translate(left, top);
|
||||
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
|
||||
ctx.drawImage(icon, -size/2, -size/2, size, size);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
function _changeColor(eventData, transform) {
|
||||
const target = transform.target;
|
||||
const _colorpicker = document.createElement('input')
|
||||
_colorpicker.setAttribute('type', 'color')
|
||||
_colorpicker.value = penColor
|
||||
|
||||
_colorpicker.addEventListener('input', function (e) {
|
||||
target.set({ fill: e.target.value })
|
||||
target.canvas.requestRenderAll()
|
||||
if(target.type != "rect") {
|
||||
storePenColor(e.target.value)
|
||||
}
|
||||
})
|
||||
|
||||
_colorpicker.click()
|
||||
_colorpicker.remove()
|
||||
}
|
||||
|
||||
function init(el) {
|
||||
colorControl = new fabric.Control({
|
||||
x: 0.5,
|
||||
y: -0.5,
|
||||
offsetY: -16,
|
||||
offsetX: 16,
|
||||
cursorStyle: 'pointer',
|
||||
mouseUpHandler: _changeColor,
|
||||
render: _renderIcon(_coloricon),
|
||||
cornerSize: 24
|
||||
})
|
||||
|
||||
el.controls.color = colorControl
|
||||
}
|
||||
|
||||
return {
|
||||
init: init
|
||||
}
|
||||
})()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
<a href="<?php echo $REVERSE_PROXY_URL; ?>/signature" class="list-group-item list-group-item-action"><i class="bi bi-people-fill"></i> <?php echo _("Allow multiple people to sign via a shared link") ?></a>
|
||||
<a href="<?php echo $REVERSE_PROXY_URL; ?>/signature" class="list-group-item list-group-item-action"><i class="bi bi-patch-check"></i> <?php echo _("Sign with the server certificate") ?></a>
|
||||
<a href="<?php echo $REVERSE_PROXY_URL; ?>/signature" class="list-group-item list-group-item-action"><i class="bi bi-droplet-half"></i> <?php echo _("Add a watermark") ?></a>
|
||||
<a href="<?php echo $REVERSE_PROXY_URL; ?>/signature" class="list-group-item list-group-item-action"><i class="bi bi-bounding-box"></i> <?php echo _("Redact areas") ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="<?php echo $TRANSLATION_LANGUAGE ?>" dir="<?php echo $DIRECTION_LANGUAGE ?>" style="direction: <?php echo $DIRECTION_LANGUAGE ?>;">
|
||||
<head>
|
||||
<?php include('components/header.html.php'); ?>
|
||||
<link href="<?php echo $REVERSE_PROXY_URL; ?>/css/pdf_viewer.css" rel="stylesheet">
|
||||
<title>Signature PDF - Éditer les métadonnées</title>
|
||||
<meta name="description" content="Logiciel libre en ligne qui permet d'jouter, modifier ou supprimer les métadonnées d'un PDF">
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -83,14 +83,17 @@
|
|||
<input type="radio" class="btn-check" id="radio_svg_check" data-height="18" name="svg_2_add" autocomplete="off" value="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0iYmkgYmktY2hlY2stbGciIHZpZXdCb3g9IjAgMCAxNiAxNiI+CiAgPHBhdGggZD0iTTEyLjczNiAzLjk3YS43MzMuNzMzIDAgMCAxIDEuMDQ3IDBjLjI4Ni4yODkuMjkuNzU2LjAxIDEuMDVMNy44OCAxMi4wMWEuNzMzLjczMyAwIDAgMS0xLjA2NS4wMkwzLjIxNyA4LjM4NGEuNzU3Ljc1NyAwIDAgMSAwLTEuMDYuNzMzLjczMyAwIDAgMSAxLjA0NyAwbDMuMDUyIDMuMDkzIDUuNC02LjQyNWEuMjQ3LjI0NyAwIDAgMSAuMDItLjAyMloiLz4KPC9zdmc+Cg==">
|
||||
<label draggable="true" id="label_svg_check" class="btn btn-outline-secondary text-black text-start btn-svg" for="radio_svg_check"><?php echo sprintf(_("%s Check box"), '<i class="bi bi-check-square"></i>'); ?></label>
|
||||
</div>
|
||||
|
||||
<?php if (! isset($hash)): ?>
|
||||
<div class="d-grid gap-2 mb-2 list-item-add">
|
||||
<input type="radio" class="btn-check" id="radio_svg_rectangle" name="svg_2_add" autocomplete="off" value="rectangle" data-svg="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0iYmkgYmktYm91bmRpbmctYm94IiB2aWV3Qm94PSIwIDAgMTYgMTYiPg0KICA8cGF0aCBkPSJNNSAyVjBIMHY1aDJ2NkgwdjVoNXYtMmg2djJoNXYtNWgtMlY1aDJWMGgtNXYyem02IDF2MmgydjZoLTJ2Mkg1di0ySDNWNWgyVjN6bTEtMmgzdjNoLTN6bTMgMTF2M2gtM3YtM3pNNCAxNUgxdi0zaDN6TTEgNFYxaDN2M3oiLz4NCjwvc3ZnPg==">
|
||||
<label draggable="true" id="label_svg_rectangle" class="btn btn-outline-secondary text-black text-start btn-svg" for="radio_svg_rectangle"><i class="bi bi-bounding-box"></i> <?php echo _("Redaction area"); ?></label>
|
||||
</div>
|
||||
<div class="input-watermark-placeholder btn btn-outline-secondary w-100 text-start text-dark">
|
||||
<span class="bi bi-droplet-half" id="watermark-addon"></span> <?php echo _("Watermark") ?>
|
||||
</div>
|
||||
<div class="input-group d-none">
|
||||
<span class="input-group-text border-secondary"><i class="bi bi-droplet-half"></i></span>
|
||||
<input form="form_pdf" type="text" class="form-control border-secondary" name="watermark" placeholder="<?php echo _("Watermark") ?>" aria-label="Watermark" aria-describedby="watermark-addon" maxlength="30">
|
||||
<input form="form_pdf" type="text" class="form-control border-secondary" name="watermark" placeholder="<?php echo _("Watermark") ?>" aria-label="Watermark" aria-describedby="watermark-addon">
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
|
|
@ -107,8 +110,9 @@
|
|||
<form id="form_pdf" action="<?php echo $REVERSE_PROXY_URL; ?>/sign" method="post" enctype="multipart/form-data" class="d-none d-sm-none d-md-block">
|
||||
<input id="input_pdf" name="pdf" type="file" class="d-none" />
|
||||
<input id="input_svg" name="svg[]" type="file" class="d-none" />
|
||||
<button class="btn btn-primary w-100 mt-2" disabled="disabled" type="submit" id="save"><i class="bi bi-download"></i> <?php echo _("Download the signed PDF"); ?></button>
|
||||
</form>
|
||||
<input name="flatten" type="checkbox" value="1" class="d-none" />
|
||||
<button class="btn btn-primary w-100 mt-2 w-100" disabled="disabled" type="submit" id="save"><i class="bi bi-download"></i> <?php echo _("Download the signed PDF"); ?> <i id="save_flatten_indicator" class="bi bi-layers-half opacity-50 float-end invisible" title="<?php echo _("The PDF will be flattened") ?>"></i></button>
|
||||
</form>
|
||||
<?php elseif(!isset($noSharingMode)): ?>
|
||||
<div class="d-none d-sm-none d-md-block position-relative">
|
||||
<a id="btn-signature-help" class="position-absolute top-0 end-0 text-dark" href="" style="z-index: 5;"><i class="bi bi-question-circle"></i></a>
|
||||
|
|
@ -181,8 +185,9 @@
|
|||
</div>
|
||||
<input id="input-svg-type" type="hidden" />
|
||||
</div>
|
||||
<div class="modal-footer d-block">
|
||||
<div class="modal-footer justify-content-between">
|
||||
<button tabindex="-1" type="button" class="btn btn-light col-4" data-bs-dismiss="modal"><?php echo _("Cancel"); ?></button>
|
||||
<input type="color" id="penColorPicker" class="form-control form-control-color">
|
||||
<button id="btn_modal_ajouter" type="button" disabled="disabled" data-bs-dismiss="modal" class="btn btn-primary float-end col-4"><span id="btn_modal_ajouter_spinner" class="spinner-border spinner-border-sm d-none"></span><span id="btn_modal_ajouter_check" class="bi bi-check-circle"></span> <?php echo _("Create"); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue