OS – macOS Sonoma
I am trying to capture images of all the tabs of a Chrome Window, B which is launched by another Chrome Window, A. This process is part of an extension. Following are the possibilities
B can be in
- foreground
- background of A
- background of any other Application window like Slack, for example
Workflow is
- extension loads code where Window A, with relevant permission activeTab, opens Window B.
- Window B opens 4 tabs, where first tab contains Take Screenshot button.
- User takes action on a Button on first Tab of Window B to initiate screenshot capture. 4. Algorithm triggers that iteratively makes every tab is active and injects a script is in active Tab’s foreground, which sends the message to the background to take screenshot.
Following is the code
manifest.json
{
"manifest_version": 3,
"name": "Screenshot Extension",
"version": "1.0",
"permissions": [
"tabs", "scripting", "activeTab"],
"host_permissions": [
"<all_urls>",
"*://*/*",
"http://*/*",
"https://*/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon.png",
"48": "images/icon.png",
"128": "images/icon.png"
}
}
}
content.js
// Connect to the background script
//const port = chrome.runtime.connect();
console.log('in content script');
// Get the current window ID
chrome.runtime.sendMessage({ action: "captureTab" }, (response) => {
console.log('logging status: ' + response.status);
if (response.dataUrl) {
// Optionally handle the captured image data URL here
console.log('Captured image URL:', response.dataUrl);
}
});
background.js
let captureVisibleTab;
let cwid;
let windowBId;
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "createWindowB",
title: "Create Window B",
contexts: ["action"]
});
});
chrome.runtime.onInstalled.addListener(() => {
console.log('launching window');
createWindowB();
//setTimeout(startTakingScreenshots, 3000);
});
/*
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "createWindowB") {
createWindowB();
}
});*/
function createWindowB() {
const urls = [
chrome.runtime.getURL("permission.html"),
"/",
"https://google.com/",
"https://cricbuzz.com/"
];
chrome.windows.create({
url: urls,
type: "normal",
focused: true
}, (window) => {
windowBId = window.id;
console.log('Window B created with ID:', window.id);
});
}
// Listener for messages to start the screenshot process
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'startScreenshots') {
console.log('received start taking screen shots');
startTakingScreenshots();
}
});
//startTakingScreenshots();
function startTakingScreenshots() {
chrome.tabs.query({ windowId: windowBId}, (tabs) => {
tabs.forEach((tab, index) => {
if (index > 0) { // Skip the first tab (index 0)
setTimeout(() => {
console.log('starting to take screenshot');
chrome.tabs.update(tab.id, { active: true }, () => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['content.js']
});
});
}, index * 6000); // Delay to allow the tab to activate and render
}
});
});
}
/*
function captureTab() {
chrome.tabs.captureVisibleTab(null, { format: 'png' }, (dataUrl) => {
console.log('Captured tab image data URL:', dataUrl);
});
}
*/
captureVisibleTab = (callback) => {
chrome.windows.getCurrent((currentWindow) => {
cwid = currentWindow.id;
console.log(`Current window ID: ${cwid} & window B id: ${windowBId}`);
});
if (cwid !== windowBId) return;
console.log('invoking captured tab with current window id: ' + cwid);
chrome.tabs.captureVisibleTab(windowBId, { format: 'png' }, (dataUrl) => {
console.log('Captured tab image data URL:', dataUrl);
// Pass the dataUrl to the callback
if (callback) callback(dataUrl);
});
};
//setTimeout(captureVisibleTab, 1000);
// Listener to handle messages from the content script
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "captureTab" && captureVisibleTab) {
captureVisibleTab((dataUrl) => {
console.log(dataUrl);
sendResponse({ status: "Captured", dataUrl: dataUrl });
});
// Return true to indicate that we will respond asynchronously
return true;
}
});
windowB.js
document.getElementById('startScreenshots').addEventListener('click', () => {
chrome.runtime.sendMessage({ action: 'startScreenshots' });
});
permission.html
<!DOCTYPE html>
<html>
<head>
<title>Window B</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
button {
padding: 10px 20px;
font-size: 16px;
}
</style>
</head>
<body>
<h1>Take Screenshots</h1>
<button id="startScreenshots">Start Taking Screenshots</button>
<script src="windowB.js"></script>
</body>
</html>
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mouse Cursor Mover</title>
</head>
<body>
<h1>Click to Move Mouse Cursor</h1>
</body>
</html>
Observations: on loading extension, Window B is launched. I click on the button in the first tab to take snapshot, i observe the following behaviour
- Window B is foreground – Success (Screenshots of Tabs are captured)
- Window B is in background of another Application – Success
- Window B is in background of Window A, and completely overshadowed by it – Failure
- Window B is in background of Window A, and visible even by smallest of margin behind Window A – Success
- Window B is minimized – Failure
I can think of the reason of working of scenarios 1 and probably of 5, however, I cannot work out reason why 2 & 4 works while 3 fails.
Will appreciate suggestions or probably pointing out if I overlooked any point here.