Created
July 9, 2026 21:53
-
-
Save ameboide/0341e235bedda3f232f164f0359a1d50 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Embiggen Images | |
| // @namespace ameboide | |
| // @author ameboide | |
| // @description Shows CSS-resized images (and some thumbnails) in their original size by holding Shift while hovering over the image (or links to images) | |
| // @include * | |
| // @version 1.13 | |
| // @grant none | |
| // ==/UserScript== | |
| var show = false; | |
| var keep = false; | |
| var testing = null; | |
| var keyShow = 16; //shift | |
| var keyKeep = 18; //alt | |
| //match common thumbnail urls | |
| var reThumb = [ | |
| [/(wikipedia\/commons\/)thumb\/(.+)\/\d+px[^\/]+$/, '$1$2'], //wikipedia | |
| [/(-|_)\d+x\d+(?=\.\w+$)|:thumb$|(_mini|_reasonably_small|_normal|_bigger)(?=\.\w+$)|\?(w|h)=\d+&(w|h)=\d+$/, ''], | |
| [/(\.gravatar\.com\/avatar\/\w+)(\?.+)?$/, '$1?s=529'], //gravatar | |
| [/(\.gravatar\.com\/avatar)\.php\?.*gravatar_id=(\w+).*$/, '$1/$2?s=529'], //gravatar alt | |
| [/\._.+(\.\w+)$/, '$1'], //imdb, amazon | |
| [/\/mini\//, '/large/'], //twitpic | |
| [/_500(\.\w+)$/, '_1280$1'], //tumblr | |
| [/(fbcdn.+_)q(\.\w+)$/, '$1n$2'], //facebook avatars | |
| [/^.+(\?|&)url=([^&]+)(&.+)?/, '$2'], //proxy (g+) | |
| [/(\/photos\/images\/)list\//, '$1newsfeed/'], //knowyourmeme | |
| [/eldefinido.cl\/portadas\/650\//, 'eldefinido.cl/portadas/1200/'], | |
| [/(yt3.ggpht.com\/ytc\/.+=)(s\d+-)/, '$1s512-'], //youtube | |
| [/\bs=\d+\b/, ''], | |
| [/(boardgamearena.net\/.+\/avatar\/.+default-\d+)_\d+.jpg?/, '$1.jpg'], | |
| [/(boardgamearena.net\/.+\/avatar\/.+)_\d+.jpg?/, '$1_184.jpg'], | |
| ]; | |
| //match links to images | |
| var reImg = [ | |
| [/^(?!.+wikipedia.org\/wiki\/\w+:).+\.(png|jpg|jpeg|gif|svg)(\?.+)?$/, '$&'], | |
| [/^.+&imgurl=([^&]+).*$/, function(x, url){ //google images | |
| return decodeURIComponent(decodeURI(url)); | |
| }], | |
| [/(imgur\.com\/\w+)$/, 'i.$&.jpg'] | |
| ]; | |
| //match css urls | |
| var reCssUrl = /^url\("(.+)"\)$/; | |
| var lastTarget = null; | |
| var testingClass = 'testing-embiggenable'; | |
| var div, bigImg, testImg; | |
| function init(){ | |
| div = document.createElement('div'); | |
| div.style.position = 'fixed'; | |
| div.style.top = 0; | |
| div.style.left = 0; | |
| div.style.maxWidth = '100%'; | |
| div.style.maxHeight = '100%'; | |
| div.style.overflow = 'auto'; | |
| div.style.display = 'none'; | |
| div.style.zIndex = (1<<30)*2-1; //max int32 | |
| document.body.appendChild(div); | |
| bigImg = document.createElement('img'); | |
| div.appendChild(bigImg); | |
| bigImg.addEventListener('click', function(e){ | |
| fitToWindow(bigImg); | |
| }); | |
| var css = document.createElement('style'); | |
| css.innerHTML = '.'+testingClass+'{border:1px dotted red !important;}'; | |
| div.appendChild(css); | |
| testImg = document.createElement('img'); | |
| testImg.addEventListener('load', function(){ | |
| if(show && testing){ | |
| bigImg.src = testImg.src; | |
| bigImg.setAttribute('style', ''); | |
| div.style.display = ''; | |
| } | |
| endTesting(); | |
| }, true); | |
| testImg.addEventListener('error', endTesting, true); | |
| testImg.addEventListener('abort', endTesting, true); | |
| } | |
| function testTarget(element, src){ | |
| if(!div) init(); | |
| endTesting(); | |
| element.classList.add(testingClass); | |
| testing = element; | |
| testImg.src = src; | |
| } | |
| function endTesting(hide){ | |
| if(hide){ | |
| show = false; | |
| if(div) div.style.display = 'none'; | |
| } | |
| if(testing){ | |
| testing.classList.remove(testingClass); | |
| testing = null; | |
| } | |
| } | |
| function testReList(img, src, reList){ | |
| for(var i=0; i<reList.length; i++){ | |
| var re = reList[i]; | |
| if (re[0].test(src)){ | |
| testTarget(img, src.replace(re[0], re[1])); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| function processTarget(img){ | |
| var parent = img.parentNode; | |
| if(img.tagName == 'IMG'){ | |
| if(img.width != img.naturalWidth || img.height != img.naturalHeight){ | |
| testTarget(img, img.src); | |
| } | |
| if(parent.tagName == 'A' && testReList(img, parent.href, reImg)){ | |
| return true; | |
| } | |
| return testReList(img, img.src, reThumb); | |
| } | |
| if(img.tagName == 'A' && testReList(img, img.href, reImg)){ | |
| return true; | |
| } | |
| while(true){ | |
| var style = window.getComputedStyle(img); | |
| if(reCssUrl.test(style.backgroundImage)){ | |
| var src = style.backgroundImage.replace(reCssUrl, '$1'); | |
| if(style.backgroundSize != 'auto auto'){ | |
| testTarget(img, src); | |
| } | |
| return testReList(img, src, reThumb); | |
| } | |
| if(img.offsetWidth != parent.offsetWidth || img.offsetHeight != parent.offsetHeight){ | |
| return false; | |
| } | |
| //fake target? | |
| img = parent; | |
| parent = img.parentNode; | |
| } | |
| } | |
| function fitToWindow(img){ | |
| var widthRatio = img.naturalWidth / window.innerWidth; | |
| var heightRatio = img.naturalHeight / window.innerHeight; | |
| var ratio = Math.max(widthRatio, heightRatio); | |
| if(ratio > 1){ | |
| if(img.style.width){ | |
| img.style.width = ''; | |
| } | |
| else{ | |
| img.style.width = Math.floor(img.naturalWidth / ratio) + 'px'; | |
| } | |
| } | |
| } | |
| window.addEventListener('keydown', function(e){ | |
| if(e.keyCode == keyShow && !show){ | |
| show = true; | |
| if(lastTarget){ | |
| processTarget(lastTarget); | |
| } | |
| } | |
| else if(e.keyCode == keyKeep){ | |
| // keep = true; | |
| } | |
| }, true); | |
| window.addEventListener('keyup', function(e){ | |
| if(e.keyCode == keyKeep){ | |
| keep = false; | |
| } | |
| else if(!keep && e.keyCode == keyShow){ | |
| endTesting(true); | |
| } | |
| }, true); | |
| window.addEventListener('mouseover', function(e){ | |
| if(e.target == bigImg) return; | |
| lastTarget = e.target; | |
| if(show){ | |
| processTarget(lastTarget); | |
| } | |
| }, true); | |
| //left click + right click | |
| var b1 = false, stopClick = 0; | |
| window.addEventListener('mousedown', function(e){ | |
| if(b1 && e.buttons == 3){ | |
| if(show){ | |
| endTesting(true); | |
| } | |
| else{ | |
| show = true; | |
| lastTarget = e.target; | |
| processTarget(lastTarget); | |
| } | |
| stopClick = 3; | |
| } | |
| b1 = e.buttons == 1; | |
| }, true); | |
| window.addEventListener('click', function(e){ | |
| var b = e.button || 1; | |
| if(b & stopClick){ | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| stopClick ^= b; | |
| } | |
| }, true); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment