Skip to content

Commit

Permalink
[mirotalksfu] - miroslavpejic85#194 Add Virtual Background Image from…
Browse files Browse the repository at this point in the history
… URL
  • Loading branch information
miroslavpejic85 committed Feb 14, 2025
1 parent ac6f973 commit 9709acb
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 4 deletions.
2 changes: 1 addition & 1 deletion app/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ dev dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.7.37
* @version 1.7.38
*
*/

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mirotalksfu",
"version": "1.7.37",
"version": "1.7.38",
"description": "WebRTC SFU browser-based video calls",
"main": "Server.js",
"scripts": {
Expand Down
48 changes: 48 additions & 0 deletions public/css/Room.css
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,54 @@ body {
color: white;
}

/*--------------------------------------------------------------
# Custom modal to paste image URL
--------------------------------------------------------------*/

.imageUrlModal {
display: none;
position: fixed;
z-index: 9999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--body-bg);
width: 80%;
max-width: 400px;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.imageUrlModal-content {
background: var(--body-bg);
padding: 20px;
border-radius: 8px;
text-align: center;
}

.imageUrlModal input {
width: 80%;
padding: 10px;
margin: 10px 0;
border: var(--border);
border-radius: 4px;
}

.imageUrlModal button {
padding: 10px 20px;
border: none;
background: var(--btns-bg-color);
border-radius: 10px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
}

.imageUrlModal button:hover {
background: var(--body-bg) !important;
}

/*--------------------------------------------------------------
# Buttons bar
--------------------------------------------------------------*/
Expand Down
Binary file added public/images/link.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/js/Brand.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ let BRAND = {
},
about: {
imageUrl: '../images/mirotalk-logo.gif',
title: '<strong>WebRTC SFU v1.7.37</strong>',
title: '<strong>WebRTC SFU v1.7.38</strong>',
html: `
<button
id="support-button"
Expand Down
68 changes: 68 additions & 0 deletions public/js/Room.js
Original file line number Diff line number Diff line change
Expand Up @@ -5116,6 +5116,74 @@ function showImageSelector() {
imageGrid.appendChild(uploadImg);
setTippy(uploadImg.id, 'Upload your custom background', 'top');

// Function to fetch image from URL and store it in IndexedDB
async function fetchAndStoreImage(url) {
try {
const response = await fetch(url);
const blob = await response.blob();
const reader = new FileReader();

reader.onload = function (e) {
const imgData = e.target.result;
saveImageToIndexedDB(imgData);
addImageToUI(imgData);
};

reader.readAsDataURL(blob);
} catch (error) {
console.error('Error fetching image:', error);
}
}

saveImageUrlBtn.addEventListener('click', async () => {
elemDisplay(imageUrlModal.id, false);
if (isValidURL(imageUrlInput.value)) {
await fetchAndStoreImage(imageUrlInput.value);
imageUrlInput.value = '';
}
});

cancelImageUrlBtn.addEventListener('click', () => {
elemDisplay(imageUrlModal.id, false);
imageUrlInput.value = '';
});

function askForImageURL() {
elemDisplay(imageUrlModal.id, true);

// Take URL from clipboard ex:
navigator.clipboard
.readText()
.then((clipboardText) => {
if (!clipboardText) return false;
const sanitizedText = filterXSS(clipboardText);
if (isValidURL(sanitizedText) && imageUrlInput) {
imageUrlInput.value = sanitizedText;
}
return false;
})
.catch(() => {
return false;
});
}

// Function to validate URL format
function isValidURL(url) {
return (
url.match(/\.(jpeg|jpg|png|gif|webp|bmp|svg|apng|avif|heif|heic|tiff?|ico|cur|jfif|pjpeg|pjp|raw)$/i) !==
null
);
}

// Create link to upload image
const linkImg = document.createElement('img');
linkImg.id = 'linkImage';
linkImg.src = image.link;
linkImg.alt = 'Link image';
linkImg.addEventListener('click', askForImageURL);
imageGrid.appendChild(linkImg);
setTippy(linkImg.id, 'Upload Image from Url', 'top');

// Loop through virtual background images dynamically
virtualBackgrounds.forEach((imageUrl, index) => {
const img = document.createElement('img');
Expand Down
72 changes: 71 additions & 1 deletion public/js/RoomClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.7.37
* @version 1.7.38
*
*/

Expand Down Expand Up @@ -114,6 +114,7 @@ const image = {
transcription: '../images/transcription.png',
back: '../images/back.png',
blur: '../images/blur.png',
link: '../images/link.png',
upload: '../images/upload.png',
virtualBackground: {
one: '../images/virtual-background/background-1.jpg',
Expand Down Expand Up @@ -1837,6 +1838,75 @@ class RoomClient {
imageGridVideo.appendChild(uploadImg);
setTippy(uploadImg.id, 'Upload your custom background', 'top');

// Function to fetch image from URL and store it in IndexedDB
async function fetchAndStoreImage(url) {
try {
const response = await fetch(url);
const blob = await response.blob();
const reader = new FileReader();

reader.onload = function (e) {
const imgData = e.target.result;
saveImageToIndexedDB(imgData);
addImageToUI(imgData);
};

reader.readAsDataURL(blob);
} catch (error) {
console.error('Error fetching image:', error);
}
}

saveImageUrlBtn.addEventListener('click', async () => {
elemDisplay(imageUrlModal.id, false);
if (isValidURL(imageUrlInput.value)) {
await fetchAndStoreImage(imageUrlInput.value);
imageUrlInput.value = '';
}
});

cancelImageUrlBtn.addEventListener('click', () => {
elemDisplay(imageUrlModal.id, false);
imageUrlInput.value = '';
});

function askForImageURL() {
elemDisplay(imageUrlModal.id, true);

// Take URL from clipboard ex:
navigator.clipboard
.readText()
.then((clipboardText) => {
if (!clipboardText) return false;
const sanitizedText = filterXSS(clipboardText);
if (isValidURL(sanitizedText) && imageUrlInput) {
imageUrlInput.value = sanitizedText;
}
return false;
})
.catch(() => {
return false;
});
}

// Function to validate URL format
function isValidURL(url) {
return (
url.match(
/\.(jpeg|jpg|png|gif|webp|bmp|svg|apng|avif|heif|heic|tiff?|ico|cur|jfif|pjpeg|pjp|raw)$/i,
) !== null
);
}

// Create link to upload image
const linkImg = document.createElement('img');
linkImg.id = 'linkImage';
linkImg.src = image.link;
linkImg.alt = 'Link image';
linkImg.addEventListener('click', askForImageURL);
imageGridVideo.appendChild(linkImg);
setTippy(linkImg.id, 'Upload Image from Url', 'top');

// Loop through virtual background images dynamically
virtualBackgrounds.forEach((imageUrl, index) => {
const img = document.createElement('img');
Expand Down
8 changes: 8 additions & 0 deletions public/views/Room.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ <h1>Loading</h1>
</div>
</div>
<div id="usernameEmoji" class="usernameEmoji fadein center hidden"></div>
<div id="imageUrlModal" class="imageUrlModal">
<div class="imageUrlModal-content fadein">
<h2>Paste Image URL</h2>
<input type="text" id="imageUrlInput" placeholder="Enter the image URL here..." />
<button id="saveImageUrlBtn">Save</button>
<button id="cancelImageUrlBtn">Cancel</button>
</div>
</div>
</section>

<div id="control" class="fadein">
Expand Down

0 comments on commit 9709acb

Please sign in to comment.