您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds context menu options to view an image in a new tab with dynamic background controls, and to change the background directly behind the image on the current page (white, black, transparent, reset).
// ==UserScript== // @name image color viewer.js // @namespace github.com/annaprojects // @version 1.3 // @description Adds context menu options to view an image in a new tab with dynamic background controls, and to change the background directly behind the image on the current page (white, black, transparent, reset). // @author annaroblox // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_openInTab // ==/UserScript== (function() { 'use strict'; // Variable to store the URL of the image that was right-clicked. let imageUrl = null; // Variable to store the actual DOM image element that was right-clicked. let currentImageElement = null; // Define a class name for our custom wrapper elements to easily identify them. const WRAPPER_CLASS = 'gm-image-bg-wrapper'; /** * Event listener for the 'contextmenu' event. * When a user right-clicks, this function checks if the target is an image. * If it is, both the image's source URL and the image DOM element are stored. * Otherwise, both are reset to null. */ document.addEventListener('contextmenu', function(e) { if (e.target.tagName === 'IMG') { imageUrl = e.target.src; currentImageElement = e.target; // Store the actual image element } else { imageUrl = null; currentImageElement = null; // Clear both if a non-image element is right-clicked } }, true); // Use capture phase to ensure this runs before other context menu handlers /** * Registers a context menu command for "View Image in New Tab". * When this command is selected, if an image URL is available, it opens the image * viewer in a new tab with an initial white background. The new tab will have its * own controls to change the background. */ GM_registerMenuCommand("View Image in New Tab", function() { if (imageUrl) { // Open the image viewer in a new tab, defaulting to a white background. // The new tab will contain controls to change its background dynamically. openImageViewer(imageUrl, 'white'); } }); /** * Registers a context menu command for "Set Image BG (White)". * When selected, this applies a white background directly behind the clicked image * on the current page. */ GM_registerMenuCommand("Set Image BG (White)", function() { if (currentImageElement) { setImageBackground(currentImageElement, 'white'); } }); /** * Registers a context menu command for "Set Image BG (Black)". * When selected, this applies a black background directly behind the clicked image * on the current page. */ GM_registerMenuCommand("Set Image BG (Black)", function() { if (currentImageElement) { setImageBackground(currentImageElement, 'black'); } }); /** * Registers a context menu command for "Set Image BG (Transparent)". * When selected, this applies a checkerboard background directly behind the clicked image * on the current page, simulating transparency. */ GM_registerMenuCommand("Set Image BG (Transparent)", function() { if (currentImageElement) { setImageBackground(currentImageElement, 'transparent'); } }); /** * Registers a context menu command for "Reset Image BG". * When selected, this removes any custom background wrapper applied to the clicked image, * returning it to its original state on the page. */ GM_registerMenuCommand("Reset Image BG", function() { if (currentImageElement) { resetImageBackground(currentImageElement); } }); /** * Applies a background color or pattern behind the given image element on the current page. * It either creates a new wrapper div or updates an existing one. * * @param {HTMLElement} imageElement - The <img> element to apply the background to. * @param {string} bgColor - The desired background color ('white', 'black', or 'transparent'). */ function setImageBackground(imageElement, bgColor) { const parent = imageElement.parentNode; let wrapper = null; // Check if the image is already inside one of our wrappers if (parent && parent.classList && parent.classList.contains(WRAPPER_CLASS)) { wrapper = parent; } else { // Create a new wrapper div wrapper = document.createElement('div'); wrapper.classList.add(WRAPPER_CLASS); // Mark it with our custom class wrapper.style.display = 'inline-flex'; // Use inline-flex to wrap content and allow centering wrapper.style.alignItems = 'center'; wrapper.style.justifyContent = 'center'; wrapper.style.padding = '10px'; // Padding to show the background wrapper.style.borderRadius = '8px'; // Rounded corners for the background wrapper.style.boxShadow = '0 4px 10px rgba(0,0,0,0.2)'; // Subtle shadow wrapper.style.transition = 'background-color 0.3s ease, background-image 0.3s ease'; // Smooth transitions wrapper.style.lineHeight = '0'; // Prevent extra space below image due to line-height // Insert the wrapper before the image, then append the image to the wrapper parent.insertBefore(wrapper, imageElement); wrapper.appendChild(imageElement); } // Apply the chosen background style to the wrapper if (bgColor === 'transparent') { wrapper.style.backgroundImage = 'linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)'; wrapper.style.backgroundSize = '20px 20px'; wrapper.style.backgroundPosition = '0 0, 0 10px, 10px -10px, -10px 0px'; wrapper.style.backgroundColor = ''; // Clear solid color if any } else { wrapper.style.backgroundImage = 'none'; wrapper.style.backgroundSize = 'auto'; wrapper.style.backgroundPosition = 'auto'; wrapper.style.backgroundColor = bgColor; } } /** * Resets the background of an image by removing the custom wrapper. * * @param {HTMLElement} imageElement - The <img> element whose background wrapper should be removed. */ function resetImageBackground(imageElement) { const parent = imageElement.parentNode; // Check if the parent is our custom wrapper if (parent && parent.classList && parent.classList.contains(WRAPPER_CLASS)) { const grandParent = parent.parentNode; if (grandParent) { // Move the image back to its original parent's position grandParent.insertBefore(imageElement, parent); // Remove the wrapper div grandParent.removeChild(parent); } } } /** * Opens a new tab with the image viewer HTML content. * The HTML includes the image and controls to change the background color dynamically. * * @param {string} url - The URL of the image to display. * @param {string} initialBgColor - The initial background color ('white', 'black', or 'transparent'). */ function openImageViewer(url, initialBgColor) { // Construct the HTML content for the new image viewer tab. // It includes basic styling, the image, and JavaScript functions for changing the background. const imageViewerHTML = ` <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Image Viewer</title> <!-- Link to Google Fonts for Inter font --> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet"> <style> /* Basic body styling for centering content and smooth background transitions */ body { background-color: ${initialBgColor}; /* Set the initial background color */ margin: 0; display: flex; flex-direction: column; /* Stack controls and image vertically */ justify-content: center; align-items: center; min-height: 100vh; /* Full viewport height */ transition: background-color 0.3s ease; /* Smooth transition for background changes */ font-family: 'Inter', sans-serif; /* Apply Inter font */ color: #333; /* Default text color */ overflow: hidden; /* Prevent scrollbars if image is slightly larger */ } /* Styling for the control buttons container */ .controls { position: fixed; /* Keep controls visible even when scrolling (though this page won't scroll much) */ top: 20px; /* Position from the top */ left: 50%; /* Center horizontally */ transform: translateX(-50%); /* Adjust for true centering */ background-color: rgba(255, 255, 255, 0.9); /* Semi-transparent white background for controls */ padding: 10px 20px; border-radius: 10px; /* Rounded corners for the control panel */ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); /* Subtle shadow for depth */ display: flex; /* Use flexbox for button layout */ gap: 10px; /* Space between buttons */ z-index: 1000; /* Ensure controls are on top of other content */ } /* Styling for the individual background change buttons */ .controls button { padding: 8px 15px; border: none; /* No default border */ border-radius: 5px; /* Rounded corners for buttons */ cursor: pointer; /* Indicate interactivity */ font-size: 14px; font-weight: 500; transition: background-color 0.2s ease, transform 0.1s ease; /* Smooth hover and click effects */ background-color: #007bff; /* Primary blue color for buttons */ color: white; /* White text on buttons */ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Small shadow for buttons */ } /* Hover effect for buttons */ .controls button:hover { background-color: #0056b3; /* Darker blue on hover */ transform: translateY(-1px); /* Slight lift effect */ } /* Active (clicked) effect for buttons */ .controls button:active { transform: translateY(1px); /* Slight press effect */ } /* Styling for the image itself */ img { max-width: 95%; /* Image takes up to 95% of the viewport width */ max-height: 95vh; /* Image takes up to 95% of the viewport height */ object-fit: contain; /* Ensures the entire image is visible within its bounds */ border-radius: 8px; /* Rounded corners for the image */ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25); /* More prominent shadow for the image */ margin-top: 80px; /* Push image down to clear controls */ } /* Responsive adjustments for smaller screens */ @media (max-width: 600px) { .controls { flex-direction: column; /* Stack buttons vertically on small screens */ width: 80%; /* Wider control panel */ top: 10px; } .controls button { width: 100%; /* Full width buttons */ } img { margin-top: 150px; /* Adjust margin for stacked controls */ } } </style> </head> <body> <!-- Control panel for changing background colors --> <div class="controls"> <button onclick="changeBg('white')">White Background</button> <button onclick="changeBg('black')">Black Background</button> <button onclick="changeBg('transparent')">Transparent Background</button> </div> <!-- The image display area --> <img src="${url}" alt="Image Viewer"> <script> /** * JavaScript function to dynamically change the body's background. * This function is called by the buttons in the control panel within the new tab. * @param {string} color - The desired background color ('white', 'black', or 'transparent'). */ function changeBg(color) { const body = document.body; if (color === 'transparent') { // For a 'transparent' background, apply a checkerboard pattern // This simulates transparency on a webpage that doesn't have a true transparent layer beneath it. body.style.backgroundImage = 'linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%)'; body.style.backgroundSize = '20px 20px'; // Size of each checkerboard square body.style.backgroundPosition = '0 0, 0 10px, 10px -10px, -10px 0px'; // Offset for checkerboard pattern body.style.backgroundColor = ''; // Clear any solid background color body.style.color = '#333'; // Default text color for checkerboard } else { // For solid colors, clear the checkerboard and set the solid color body.style.backgroundImage = 'none'; // Remove checkerboard pattern body.style.backgroundSize = 'auto'; body.style.backgroundPosition = 'auto'; body.style.backgroundColor = color; // Set the solid background color // Adjust text color for readability body.style.color = (color === 'black') ? '#eee' : '#333'; } } </script> </body> </html> `; // Create a Blob from the HTML string. This allows us to create a URL for the HTML content. const blob = new Blob([imageViewerHTML], { type: 'text/html' }); // Create a URL for the Blob. This URL can be opened in a new tab. const blobURL = URL.createObjectURL(blob); // Open the new tab using Tampermonkey's GM_openInTab function. GM_openInTab(blobURL, { active: true, insert: false }); // Optional: Revoke the Blob URL after a short delay. // This frees up memory, as the browser will have already loaded the content from the URL. setTimeout(() => { URL.revokeObjectURL(blobURL); }, 1000); } })();