How to overlay images by using Greasemonkey

HaD_frame

Today we’re going to take a look at writing scripts for the Greasemonkey add-on for Firefox. This add-on allows us to use JavaScript to make changes to the way webpages are displayed on our browser. These changes can only be seen by a copy of Firefox that is running a particular script. As an example, we’re going to write a script that adds a border to the banner image of each article on Hack a Day by overlaying the image you see above. Find out how it’s done after the break.

Our Goal:

We want to make the top image for each article look like it has been printed with a white border and then taped on each corner to the page. This is an effect that we used to use on our posts and a Greasemonkey script is a good way to re-implement the effect if you miss that image style.

What You Need:

  1. Install Firefox
  2. Install the Greasemonkey add-on.
  3. Download and install our script: hackaday_nostalgia.user.js

How It Works:

Greasemonkey runs JavaScript on top of the pages that have been loaded by Firefox. The first part of the file is a set of comments that tell Greasemonkey what it’s dealing with:

// ==UserScript==
// @name           Hackaday Nostalgia
// @namespace      http://hackaday.com
// @description    Overlay photograph border and taped corners for article images at Hack a Day.
// @include        http://hackaday.com/*
// ==/UserScript==

The name, namespace, and include lines are all required for the script to work. Name is what you want to call your script. Namespace is a URL that identifies the script uniquely in case there are two scripts with the same name. Include tells Greasemonkey what pages this script should be applied to. In our case we only want to monkey with the images on hackaday.com so we’ve included all addresses from that domain.

Now that we’ve identified what pages we want to alter, we can parse the document and pull out the elements we want ot change. The first thing to do is examine the page source of our target:

<div class='snap_preview'><p><img class="alignnone size-full wp-image-17747" title="plotter-with-300w-laser" src="http://hackadaycom.files.wordpress.com/2009/10/plotter-with-300w-laser.jpg?w=470&h=313" alt="plotter-with-300w-laser" width="470" height="313" /></p>

With a little digging we can find the line you see above that includes the IMG element for the title of a post. We’re in luck, the page builds each post wrapped in a DIV of the Class ‘snap-preview’. We can use Greasemonkey to parse the page looking for these DIVs and then alter the first IMG element in each one:

//get all DIVs of the snap_preview class
var allDivs, thisDiv;
allDivs = document.evaluate(
 "//div[@class='snap_preview']",
 document,
 null,
 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
 null);

In the code above we are using the evaluate function to pick out DIVs that are in the ‘snap-preview’ class. We load them into an array called allDivs which we can then step through:

//step through each DIV
for (var i=0; i<allDivs.snapshotLength; i++) {
 thisDiv = allDivs.snapshotItem(i);

 //Alter the first img of each DIV
 var image = thisDiv.getElementsByTagName('img');

 //Make sure we've got an IMG in this DIV
 if (image[0]) {

 //Save original source URL
 var orig_src = image[0].src;
 //Concatenate for CSS use
 orig_src = 'url(' + orig_src + ')';
 //Set original as background
 image[0].style.background = orig_src;

 //Set Hack a Day overlay as image
 image[0].src = 'http://hackadaycom.files.wordpress.com/2009/10/had_frame.png';
 }
}

This block of code is where the magic happens. A loop is used to step through each DIV we grabbed in the previous code snippet. We grab the IMG element by using the getElementsByTagName function. All IMG elements are put into an array called ‘image’, but we only want to alter the first image in each post so we’ll always reference image[0].

For the image border and tape effect, we used the GIMP to create a PNG file that has transparency where we want the original picture to show through. We need the original picture to be behind the overlay so we’re making it a background image using the CSS property ‘background’. The PNG overlay is then set as the new SRC for the IMG element.

That’s all it takes, now images will be overlayed with the border image you see at the top of this post.

Benefits and Drawbacks:

There are some drawbacks to using this system; the overlay covers up the borders of the original image, older posts that already have this image effect will have it applied again, the overlay will be stretched to match each original image which can look weird depending on image height, and the overlay image we’ve provide is of rather low quality (you can probably do better yourself).

Our method uses a very small amount of code and doesn’t require the original image size to be recalculated.

The Next Step:

Now that we’ve showed you how to do this much, you may want to take it one step further. The original picture style also made the images black and white. Can you make the script do this as well? To get started in the right direction, you might want to look at the Pixastic JavaScript image manipulation library and its desaturate function.

Overwhelmed?

If you need some help deciphering what we did here just use your online resources:

Comments

  1. tj says:

    Anyone know a plugin or extension that blocks cross domain content and CSS z-order? I can’t stand the new ad systems that replaced popups.

  2. chris says:

    Opera allows you to click and block images from web pages. Opera also has the functionality to change how the website is displayed locally. For example, I chose black and white, and now all the pages I view in Opera have a black background with white text. Makes surfing the web much easier on the eyes.

  3. MarkyB86 says:

    chris, internet explorer and all older web browsers do this since the dawn of the internet LOL

  4. MarkyB86 says:

    the color part I meant

  5. J H says:

    If you’ve got Firefox, get the Ghostery add-on. It removes everything, so to speak. It even cuts out the ad at the top of the hackaday site. It also usually makes some ads blank, ie the section is still there, but the content is gone.

  6. red9987 says:

    tj,
    the “Remove it Permanently” addon for firefox works great for what you are trying to do.. you just have to set it up the first time you encounter something you don’t want to see, and its gone for good… a little learning curve, but spend a few minutes playing with it, and you’ll understand.

    https://addons.mozilla.org/en-US/firefox/addon/521

  7. octel says:

    @tj
    Get noscript for the XSS & Javascript/DHTML ads (it can also replace active content such as flash with placeholder which you click to trigger the content)

    As for ads, just get Adblock Plus. The subscription (at least the US one) has filter rules for most CSS-based ads.
    Like red9987, I also recommend Remove It Permanently.

  8. hex4def6 says:

    Why’d Hackaday remove that effect? I kinda liked it; it made the page more distinctive..

  9. M4CGYV3R says:

    I might see this if I didn’t have AdBlocker+ killing them off…

  10. TJ says:

    Run a 64-bit browser, nothing works in those d8)

    Well, that’s not true, but, there’s no flash support for non-linux on 64-bit right now, and to be honest I don’t really miss the flash since 99% of the time it’s for ads.

    For the rest AdBlockPro as previously recommended and NoScript to have javascript off by default.

  11. pod says:

    I liked the b/w images too..
    any way to apply a filter to have this back too?

  12. Znegl says:

    This is the most extreeme overkill i’ve ever seen!!
    It could be done with arround 10 lines of CSS and work on all browsers :S

  13. octel says:

    @Znegl
    cool story bro, but you can’t do image manipulation like this in CSS unless you pre-render the effects and use something like mouseover image replacement/overlay

    these effects are being applied dynamically

  14. ReKlipz says:

    Why are you looping?

    Unless I’m misunderstanding how greasemonkey works, doesn’t it just run your script against the current page?

    In that case, nix the loop, make sure the image exists, and do the mods. You may not even need to check for an existing image, depends on greasemonkey functionality. Also might be able to nix the array, but not a huge issue.

  15. Mike Szczys says:

    @ReKlipz: Some stories don’t have an IMG element because they use embedded video at the top. That’s the reason to check to make sure we’ve captured the right element.

    I looped because that’s how I wrote it. Optimization suggestions are always welcomed.

  16. kwah says:

    You can get rid of the need to loop at all by changing the xPath criteria to “//div[@class='snap_preview'] //img” .

    I’ve stated this in the comment too, but it looks for IMG tags that have a DIV parent of the ‘snap_preview’ class — this removes the need to grab them via a loop because the javascript.evaluate() is doing the hard work for you..

    // grab all <img>s that have a parent <div class='snap_preview'>
    var imageSearch = document.evaluate(
     "//div[@class='snap_preview'] //img",
     document,
     null,
     XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
     null);
    
    //Check to see if any images have been found
    if(imageSearch.snapshotLength > 0)
    {
      var image = image.snapshotItem(0);
    
     //Save original source URL
     var orig_src = image.src;
     //Concatenate for CSS use
     orig_src = 'url(' + orig_src + ')';
     //Set original as background
     image.style.background = orig_src;
    
     //Set Hack a Day overlay as image
     image.src = 'http://hackadaycom.files.wordpress.com/2009/10/had_frame.png';
    
    }

    (note: consider this code as untested / provided ‘as-is’.. it might work / it might not — i’m too lazy to properly test it =P )

  17. Znegl says:

    @octel But you don’t have to do image manipulation.. Just lay a transparent png with a border on top of the original image – no-one will ever notis.. (unless they try to download the picture). After all it seems wrong to make something that only works in FF with a special plugin installed..

  18. Eric says:

    I have an IPB based forum, and we removed the admin console link and changed the adcon directory. We use greasemonkey to reinsert the admin console link so to the admins, it looks as if nothing has changed, so to anybody else, it’s a real bitch to try and type in the directory name of random characters, if you don’t know what you’re looking for.

  19. octel says:

    @Znegl
    You’re conflating Greasemonkey with the Pixastic JS library.

    Yes, there might be a way to create a border with CSS only, but that method only works for images of a known size. This border tutorial is just an example of how to use Javascript and traversing the DOM tree. Check out userscripts.org for some really amazing and advanced scripts

  20. Wwhat says:

    Clearly this article is meant to push greasemonkey into your eye, and I approve since I like greasemonkey and it comes in very handy lots of times.
    He should have linked to userscripts.org too though as octel mentioned, because that’s where people submit their own creations for greasemonkey and you can peruse what’s available.

  21. moo says:

    HackADay has ads?

  22. Brad says:

    I would be inline with moo, HackADay has adds? All I use is NoScript, improves page load times as well. I personally block most scripting, of course NoScript does not block GreaseMonkey scripts as they are implemented via post processing. You may have to disallow a few defaults (i.e. googlesyndication, etc) to remove all unwanted content. GreaseMonkey then can be used to clean up the final result.

  23. whiskey says:

    Well this is kinda lame… I mean, aren’t you hackers and stuff?

    Is it so difficult to:
    1. set up a php script that copies the image and transforms it using GD (you know, like imgred but just for you)
    2. set up a rewrite rule so that said image can be easily called with or without the border.
    3. set your template to automatically transform the image call for the front page but not for the full article.

    However there’s a simpler way to achieve this… It’s called CSS.

    And if you (out of all people) don’t know how to achieve this without resorting to client side, then everything is lost!

  24. mutant says:

    To those who commented on the looping. The loop simply applies the effect to each image. This could’ve been done much easier by using document.getElementsByTagName(‘img’).length to calculate the number of images on the page to know when to end the loop. I’ve used a method like this before with good results. In fact, I’ll leave this here. It’s inline JS that when run via the address bar will replace all images on the page with a mudkip.. becuase… ya know.. I herd u liek mudkipz.

    javascript:var num=document.getElementsByTagName(‘img’).length;for(i=0;i<num;i++){void(document.getElementsByTagName('img')[i].src="http://mudkipz.net/Emerald-Mudkip.png&quot;)}

    Enjoy

  25. mutant says:

    wtf.. how come when copied from here.. my previous inline js doesnt work.. some sort of formatting error.. but i can’t see a difference in it from the original..
    o.O

  26. mutant says:

    sorry for the triple post. I’ll just archive the js here. This should work when ran inline.

    http://pastebin.com/f6c4a461c

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 96,562 other followers