[mirotalksfu] - add pdf to whiteboard
هذا الالتزام موجود في:
@@ -812,6 +812,7 @@ function startServer() {
|
|||||||
|
|
||||||
// let objLength = bytesToSize(Object.keys(data).length);
|
// let objLength = bytesToSize(Object.keys(data).length);
|
||||||
// log.debug('Send Whiteboard canvas JSON', { length: objLength });
|
// log.debug('Send Whiteboard canvas JSON', { length: objLength });
|
||||||
|
|
||||||
room.broadCast(socket.id, 'wbCanvasToJson', data);
|
room.broadCast(socket.id, 'wbCanvasToJson', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ const userAgent = navigator.userAgent.toLowerCase();
|
|||||||
const isTabletDevice = isTablet(userAgent);
|
const isTabletDevice = isTablet(userAgent);
|
||||||
const isIPadDevice = isIpad(userAgent);
|
const isIPadDevice = isIpad(userAgent);
|
||||||
|
|
||||||
|
const Base64Prefix = 'data:application/pdf;base64,';
|
||||||
|
|
||||||
const wbImageInput = 'image/*';
|
const wbImageInput = 'image/*';
|
||||||
|
const wbPdfInput = 'application/pdf';
|
||||||
const wbWidth = 1200;
|
const wbWidth = 1200;
|
||||||
const wbHeight = 600;
|
const wbHeight = 600;
|
||||||
|
|
||||||
@@ -169,6 +172,7 @@ function initClient() {
|
|||||||
setTippy('whiteboardUndoBtn', 'Undo', 'bottom');
|
setTippy('whiteboardUndoBtn', 'Undo', 'bottom');
|
||||||
setTippy('whiteboardRedoBtn', 'Redo', 'bottom');
|
setTippy('whiteboardRedoBtn', 'Redo', 'bottom');
|
||||||
setTippy('whiteboardImgFileBtn', 'Add image file', 'bottom');
|
setTippy('whiteboardImgFileBtn', 'Add image file', 'bottom');
|
||||||
|
setTippy('whiteboardPdfFileBtn', 'Add pdf file', 'bottom');
|
||||||
setTippy('whiteboardImgUrlBtn', 'Add image url', 'bottom');
|
setTippy('whiteboardImgUrlBtn', 'Add image url', 'bottom');
|
||||||
setTippy('whiteboardTextBtn', 'Add text', 'bottom');
|
setTippy('whiteboardTextBtn', 'Add text', 'bottom');
|
||||||
setTippy('whiteboardLineBtn', 'Add line', 'bottom');
|
setTippy('whiteboardLineBtn', 'Add line', 'bottom');
|
||||||
@@ -1278,6 +1282,9 @@ function handleButtons() {
|
|||||||
whiteboardImgFileBtn.onclick = () => {
|
whiteboardImgFileBtn.onclick = () => {
|
||||||
whiteboardAddObj('imgFile');
|
whiteboardAddObj('imgFile');
|
||||||
};
|
};
|
||||||
|
whiteboardPdfFileBtn.onclick = () => {
|
||||||
|
whiteboardAddObj('pdfFile');
|
||||||
|
};
|
||||||
whiteboardImgUrlBtn.onclick = () => {
|
whiteboardImgUrlBtn.onclick = () => {
|
||||||
whiteboardAddObj('imgUrl');
|
whiteboardAddObj('imgUrl');
|
||||||
};
|
};
|
||||||
@@ -2283,6 +2290,40 @@ function whiteboardAddObj(type) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'pdfFile':
|
||||||
|
Swal.fire({
|
||||||
|
allowOutsideClick: false,
|
||||||
|
background: swalBackground,
|
||||||
|
position: 'center',
|
||||||
|
title: 'Select the PDF',
|
||||||
|
input: 'file',
|
||||||
|
inputAttributes: {
|
||||||
|
accept: wbPdfInput,
|
||||||
|
'aria-label': 'Select the PDF',
|
||||||
|
},
|
||||||
|
showDenyButton: true,
|
||||||
|
confirmButtonText: `OK`,
|
||||||
|
denyButtonText: `Cancel`,
|
||||||
|
showClass: { popup: 'animate__animated animate__fadeInDown' },
|
||||||
|
hideClass: { popup: 'animate__animated animate__fadeOutUp' },
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
let wbCanvasPdf = result.value;
|
||||||
|
if (wbCanvasPdf && wbCanvasPdf.size > 0) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = async function (event) {
|
||||||
|
wbCanvas.requestRenderAll();
|
||||||
|
await pdfToImage(event.target.result, wbCanvas);
|
||||||
|
whiteboardIsDrawingMode(false);
|
||||||
|
wbCanvasToJson();
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(wbCanvasPdf);
|
||||||
|
} else {
|
||||||
|
userLog('error', 'File not selected or empty', 'top-end');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'text':
|
case 'text':
|
||||||
const text = new fabric.IText('Lorem Ipsum', {
|
const text = new fabric.IText('Lorem Ipsum', {
|
||||||
top: 0,
|
top: 0,
|
||||||
@@ -2342,11 +2383,73 @@ function whiteboardAddObj(type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readBlob(blob) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', () => resolve(reader.result));
|
||||||
|
reader.addEventListener('error', reject);
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPDF(pdfData, pages) {
|
||||||
|
const pdfjsLib = window['pdfjs-dist/build/pdf'];
|
||||||
|
pdfData = pdfData instanceof Blob ? await readBlob(pdfData) : pdfData;
|
||||||
|
const data = atob(pdfData.startsWith(Base64Prefix) ? pdfData.substring(Base64Prefix.length) : pdfData);
|
||||||
|
try {
|
||||||
|
const pdf = await pdfjsLib.getDocument({ data }).promise;
|
||||||
|
const numPages = pdf.numPages;
|
||||||
|
const canvases = await Promise.all(
|
||||||
|
Array.from({ length: numPages }, (_, i) => {
|
||||||
|
const pageNumber = i + 1;
|
||||||
|
if (pages && pages.indexOf(pageNumber) === -1) return null;
|
||||||
|
return pdf.getPage(pageNumber).then(async (page) => {
|
||||||
|
const viewport = page.getViewport({ scale: window.devicePixelRatio });
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
const renderContext = {
|
||||||
|
canvasContext: context,
|
||||||
|
viewport: viewport,
|
||||||
|
};
|
||||||
|
await page.render(renderContext).promise;
|
||||||
|
return canvas;
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return canvases.filter((canvas) => canvas !== null);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading PDF:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pdfToImage(pdfData, canvas) {
|
||||||
|
const scale = 1 / window.devicePixelRatio;
|
||||||
|
try {
|
||||||
|
const canvases = await loadPDF(pdfData);
|
||||||
|
canvases.forEach(async (c) => {
|
||||||
|
canvas.add(
|
||||||
|
new fabric.Image(await c, {
|
||||||
|
scaleX: scale,
|
||||||
|
scaleY: scale,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error converting PDF to images:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addWbCanvasObj(obj) {
|
function addWbCanvasObj(obj) {
|
||||||
if (obj) {
|
if (obj) {
|
||||||
wbCanvas.add(obj).setActiveObject(obj);
|
wbCanvas.add(obj).setActiveObject(obj);
|
||||||
whiteboardIsDrawingMode(false);
|
whiteboardIsDrawingMode(false);
|
||||||
wbCanvasToJson();
|
wbCanvasToJson();
|
||||||
|
} else {
|
||||||
|
console.error('Invalid input. Expected an obj of canvas elements');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
<script defer src="https://unpkg.com/@popperjs/core@2"></script>
|
<script defer src="https://unpkg.com/@popperjs/core@2"></script>
|
||||||
<script defer src="https://unpkg.com/tippy.js@6"></script>
|
<script defer src="https://unpkg.com/tippy.js@6"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="initClient()">
|
<body onload="initClient()">
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
@@ -646,6 +647,7 @@ access to use this app.
|
|||||||
<button id="whiteboardUndoBtn" class="fas fa-undo"></button>
|
<button id="whiteboardUndoBtn" class="fas fa-undo"></button>
|
||||||
<button id="whiteboardRedoBtn" class="fas fa-redo"></button>
|
<button id="whiteboardRedoBtn" class="fas fa-redo"></button>
|
||||||
<button id="whiteboardImgFileBtn" class="far fa-image"></button>
|
<button id="whiteboardImgFileBtn" class="far fa-image"></button>
|
||||||
|
<button id="whiteboardPdfFileBtn" class="far fa-file-pdf"></button>
|
||||||
<button id="whiteboardImgUrlBtn" class="fas fa-link"></button>
|
<button id="whiteboardImgUrlBtn" class="fas fa-link"></button>
|
||||||
<button id="whiteboardTextBtn" class="fas fa-spell-check"></button>
|
<button id="whiteboardTextBtn" class="fas fa-spell-check"></button>
|
||||||
<button id="whiteboardLineBtn" class="fas fa-slash"></button>
|
<button id="whiteboardLineBtn" class="fas fa-slash"></button>
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم