mirror of
https://github.com/raysan5/raylib.git
synced 2026-03-10 02:55:41 +00:00
[web] Add clipboard image implementation for web (#5614)
* Add clipboard image implementation for web * Making sure that are not malloc empty string or image
This commit is contained in:
@@ -801,35 +801,98 @@ void SetClipboardText(const char *text)
|
||||
else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
|
||||
}
|
||||
|
||||
// Async EM_JS to be able to await clickboard read asynchronous function
|
||||
EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
let items = await navigator.clipboard.read();
|
||||
for (const item of items) {
|
||||
|
||||
// Check if this item contains plain text or image
|
||||
if (item.types.includes("text/plain")) {
|
||||
const blob = await item.getType("text/plain");
|
||||
const text = await blob.text();
|
||||
window._lastClipboardString = text;
|
||||
}
|
||||
else if (item.types.find(t => t.startsWith("image/"))) {
|
||||
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = bitmap.width;
|
||||
canvas.height = bitmap.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(bitmap, 0, 0);
|
||||
|
||||
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||
|
||||
// Store image and data for the Fetch function
|
||||
window._lastImgWidth = canvas.width;
|
||||
window._lastImgHeight = canvas.height;
|
||||
window._lastImgData = imgData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
}
|
||||
});
|
||||
|
||||
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(char*, GetLastPastedText, (void), {
|
||||
var str = window._lastClipboardString || "";
|
||||
var length = lengthBytesUTF8(str) + 1;
|
||||
if (length > 1) {
|
||||
var ptr = _malloc(length);
|
||||
stringToUTF8(str, ptr, length);
|
||||
return ptr;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (window._lastImgData) {
|
||||
const data = window._lastImgData;
|
||||
if (data.length > 0) {
|
||||
const ptr = _malloc(data.length);
|
||||
HEAPU8.set(data, ptr);
|
||||
|
||||
// Set the width and height via the pointers passed from C
|
||||
// HEAP32 handles the 4-byte integers
|
||||
if (width) setValue(width, window._lastImgWidth, 'i32');
|
||||
if (height) setValue(height, window._lastImgHeight, 'i32');
|
||||
|
||||
// Clear the JS buffer so we don't fetch the same image twice
|
||||
window._lastImgData = null;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Get clipboard text content
|
||||
// NOTE: returned string is allocated and freed by GLFW
|
||||
const char *GetClipboardText(void)
|
||||
{
|
||||
/*
|
||||
// Accessing clipboard data from browser is tricky due to security reasons
|
||||
// The method to use is navigator.clipboard.readText() but this is an asynchronous method
|
||||
// that will return at some moment after the function is called with the required data
|
||||
emscripten_run_script_string("navigator.clipboard.readText() \
|
||||
.then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
|
||||
.catch(err => { console.error('Failed to read clipboard contents: ', err); });"
|
||||
);
|
||||
|
||||
// The main issue is getting that data, one approach could be using ASYNCIFY and wait
|
||||
// for the data but it requires adding Asyncify emscripten library on compilation
|
||||
|
||||
// Another approach could be just copy the data in a HTML text field and try to retrieve it
|
||||
// later on if available... and clean it for future accesses
|
||||
*/
|
||||
return NULL;
|
||||
RequestClipboardData();
|
||||
return GetLastPastedText();
|
||||
}
|
||||
|
||||
// Get clipboard image
|
||||
Image GetClipboardImage(void)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
||||
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
|
||||
|
||||
int w = 0, h = 0;
|
||||
RequestClipboardData();
|
||||
unsigned char* data = GetLastPastedImage(&w, &h);
|
||||
if (data != NULL) {
|
||||
image.data = data;
|
||||
image.width = w;
|
||||
image.height = h;
|
||||
image.mipmaps = 1;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
@@ -779,37 +779,98 @@ void SetClipboardText(const char *text)
|
||||
else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
|
||||
}
|
||||
|
||||
// Async EM_JS to be able to await clickboard read asynchronous function
|
||||
EM_ASYNC_JS(void, RequestClipboardData, (void), {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
let items = await navigator.clipboard.read();
|
||||
for (const item of items) {
|
||||
|
||||
// Check if this item contains plain text or image
|
||||
if (item.types.includes("text/plain")) {
|
||||
const blob = await item.getType("text/plain");
|
||||
const text = await blob.text();
|
||||
window._lastClipboardString = text;
|
||||
}
|
||||
else if (item.types.find(t => t.startsWith("image/"))) {
|
||||
const blob = await item.getType(item.types.find(t => t.startsWith("image/")));
|
||||
const bitmap = await createImageBitmap(blob);
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = bitmap.width;
|
||||
canvas.height = bitmap.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(bitmap, 0, 0);
|
||||
|
||||
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||
|
||||
// Store image and data for the Fetch function
|
||||
window._lastImgWidth = canvas.width;
|
||||
window._lastImgHeight = canvas.height;
|
||||
window._lastImgData = imgData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("Clipboard read() requires HTTPS/Localhost");
|
||||
}
|
||||
});
|
||||
|
||||
// Returns the string created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(char*, GetLastPastedText, (void), {
|
||||
var str = window._lastClipboardString || "";
|
||||
var length = lengthBytesUTF8(str) + 1;
|
||||
if (length > 1) {
|
||||
var ptr = _malloc(length);
|
||||
stringToUTF8(str, ptr, length);
|
||||
return ptr;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Returns the image created by RequestClipboardData from JS memory to Emscripten C memory
|
||||
EM_JS(unsigned char*, GetLastPastedImage, (int* width, int* height), {
|
||||
if (window._lastImgData) {
|
||||
const data = window._lastImgData;
|
||||
if (data.length > 0) {
|
||||
const ptr = _malloc(data.length);
|
||||
HEAPU8.set(data, ptr);
|
||||
|
||||
// Set the width and height via the pointers passed from C
|
||||
// HEAP32 handles the 4-byte integers
|
||||
if (width) setValue(width, window._lastImgWidth, 'i32');
|
||||
if (height) setValue(height, window._lastImgHeight, 'i32');
|
||||
|
||||
// Clear the JS buffer so we don't fetch the same image twice
|
||||
window._lastImgData = null;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Get clipboard text content
|
||||
// NOTE: returned string is allocated and freed by GLFW
|
||||
const char *GetClipboardText(void)
|
||||
{
|
||||
/*
|
||||
// Accessing clipboard data from browser is tricky due to security reasons
|
||||
// The method to use is navigator.clipboard.readText() but this is an asynchronous method
|
||||
// that will return at some moment after the function is called with the required data
|
||||
emscripten_run_script_string("navigator.clipboard.readText() \
|
||||
.then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
|
||||
.catch(err => { console.error('Failed to read clipboard contents: ', err); });"
|
||||
);
|
||||
|
||||
// The main issue is getting that data, one approach could be using ASYNCIFY and wait
|
||||
// for the data but it requires adding Asyncify emscripten library on compilation
|
||||
|
||||
// Another approach could be just copy the data in a HTML text field and try to retrieve it
|
||||
// later on if available... and clean it for future accesses
|
||||
*/
|
||||
return NULL;
|
||||
RequestClipboardData();
|
||||
return GetLastPastedText();
|
||||
}
|
||||
|
||||
// Get clipboard image
|
||||
Image GetClipboardImage(void)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
||||
// NOTE: In theory, the new navigator.clipboard.read() can be used to return arbitrary data from clipboard (2024)
|
||||
// REF: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read
|
||||
TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
|
||||
|
||||
int w = 0, h = 0;
|
||||
RequestClipboardData();
|
||||
unsigned char* data = GetLastPastedImage(&w, &h);
|
||||
if (data != NULL) {
|
||||
image.data = data;
|
||||
image.width = w;
|
||||
image.height = h;
|
||||
image.mipmaps = 1;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user