Building a Chrome Plugin - Image Swap it up!
Tags: javascript, webdev, beginners
Published: 2019-02-05 17:12:38

---
title: Building a Chrome Plugin - Image Swap it up!
published: true
description: How to approach building a basic Chrome plugin that features image swapping
tags: javascript, webdev, beginners
---

I'd like to start by apologising in advance for the ridiculousness of [this Chrome extension](https://github.com/daniel40392/giantbomb-ify), but hopefully it'll serve as a useful reference if you want to go build your own!

<img src="https://camo.githubusercontent.com/a4970bb797511ac525ac0fefb16f249d323ef247/68747470733a2f2f7468756d62732e6766796361742e636f6d2f436f6c6f7373616c5175617272656c736f6d6542756e6e792d73697a655f726573747269637465642e676966"/>

## From Simple Intentions...

This project was initially intended as a useful reference in the event I ever needed to go and build a new Chrome extension. The basic goal and functionality of the project was to build a Chrome extension that when clicked would swap all the images on the page.

When starting out I had selected a series of [GiantBomb](https://www.giantbomb.com/) images/gifs from the web as a starting point for what would prove to be a dumb inside joke. I wanted to be able to use web based images as well as local images in order to demonstrated the full functionality of building such an application. 

Having recently seen the [APIs you didn't know you needed](https://dev.to/mkrl/apis-you-didnt-know-you-needed-38c) article I couldn't help myself but to update the project to also be able to dynamically swap in Bill Murray & Nicolas Cage related images as well. Something I think a wider audience might appreciate.

## The Implementation

When it comes to setting up a Chrome extension your starting point lies with the manifest.json. You can think of this as a similar version of a package.json for your standard NPM project.

```json
{
  "name": "GiantBomb-ify",
  "version": "0.1",
  "manifest_version" : 2,
  "description": "Replaces all images with GB Staff",
  "icons": {
    "16": "logo-small.png",
    "48": "logo-small.png",
    "128": "logo-small.png"
  },
  "background" : {
    "scripts" : ["scripts/background.js"]
  },
  "browser_action": {
    "default_icon": "logo-small.png"
  },
  "web_accessible_resources": ["images/*.jpg"],
  "permissions": ["activeTab"]
}
```

The name, icon, version, description fields should feel somewhat familiar to NPM or React devs out there, they can be populated with pretty generic details. The other fields are worth explaining in a bit more details.

* *manifest_version*: this is specific to the Chrome API, version 2 is the current default version that should be used.

* *background*: this dictates what scripts should be running in the background once the chrome extension is enabled.

* *browser_action*: this dictates the default action that should occur when the chrome extension is added to your browser, in this instance it simply sets a default_icon.

* *web_accessible_resources*: this is required to allow public access to the images stored within the extensions codebase. Without this you may have difficulties accessing localised images.

* *permissions*: this field limits the permissions of the chrome extension to only the active Chrome tab you have open.

## The Scripts

As per the manifest.json the background.js script is the first one executed during the extensions addition to a new tab. The script is only being used here to trigger another file 'imageswap.js'. In a more generic setting the script coudl be used to add more functionality to the wider Chrome api and handle items such as firing multiple scripts or injecting global variables etc.

```javascript
chrome.browserAction.onClicked.addListener(function(tab) {
   chrome.tabs.executeScript(null, {file: "scripts/imageswap.js"});
});

```

The logic of the imageswap.js contains some very basic JS.

```javascript
var chromeExtensionId = "iaimgpoecjggdpdlmlhhidciphppgfcf"

var images = document.getElementsByTagName('img');

var gb_images = [
  "https://static.giantbomb.com/uploads/scale_medium/18/187968/2743737-yplezwp.jpg", //drew headset
  "https://pbs.twimg.com/media/BpxlFaHCYAIQvvY.jpg", //brad mohawk
  "https://static.giantbomb.com/uploads/original/7/72053/2671808-rorie.png", //rorie glasses
  "http://static.giantbomb.com/uploads/original/13/139155/2536312-2379004-jeff_headshake.gif", //jeff disapproval
  "http://static.giantbomb.com/uploads/original/17/179932/2783337-4310291077-prUNU.png", // dan creep
  "https://static.giantbomb.com/uploads/original/2/23893/2455096-1935536898-10875.jpg", // vinny alpha protocol
  "http://www.deepfreeze.it/img/j_headshots/alex_navarro.jpg", // alex smile
  "https://magnettheater.com/oldImages/headshots/large_abbyrussell_2017.jpg", // abby face
  "https://static.giantbomb.com/uploads/original/23/233047/2986879-2776158-0471975364-o4gps.gif", // jason approval
  "https://78.media.tumblr.com/e0b2ba4e1fd8b1323b4e9c88477db345/tumblr_oshzt0nUPs1u7bbkho1_400.gif", // ben disapproval
  `chrome-extension://${chromeExtensionId}/images/ryan.jpg` // local file example - ryan
]

for (var i = 0, l = images.length; i < l; i++) {
  var index = Math.floor(Math.random() * Math.floor(i%gb_images.length+1))

  // GB implementation (default)
  images[i].src = gb_images[index];

  // Nicolas Cage implementation
  // images[i].src = "https://www.placecage.com/" + images[i].width + "/" + images[i].height

  // Bill Murray Implementation
  // images[i].src = "https://fillmurray.com/" + images[i].width + "/" + images[i].height

  var prev = i
}
```

* The *chromeExtensionId* variable is used for accessing local files, if you want to use local images you will have to update this value with your own chromeExtensionId once you have followed the instructions in the projects readme. This is used  for populating the local image file ryan.jpg.

* The *images* variable is used to get all the image tags on a page.

* The *gb_images* array is used as our set of 10 GiantBomb staff images for switching

* A for loop is used to iterate through all the images on the page, and for each one it uses a randomly selected index from our gb_images array and displays that instead.

* The alternative code for implementing the Bill Murray or Nicolas Cage images follows a similar pattern except in their scenarios the height and width values of the images are used and passed into the corresponding urls to generate the associated images. 

## Sample Results

Of course I couldn't sign off without showing some quick screenshots from the results of this horrific extension...

<img src="https://thepracticaldev.s3.amazonaws.com/i/dy35pigxsp9af8yvs0l7.png"/>
<img src="https://thepracticaldev.s3.amazonaws.com/i/cwounfnyyev2v37zheap.png"/>
<img src="https://thepracticaldev.s3.amazonaws.com/i/zrxoucx0xp9uxthg3175.png"/>

A few things you can note from these screenshots:

* Yes I simply searched red in google then fired the plugin - it provides a more interesting/psychotic effect when used on Twitter/Facebook but I don't have the time to censor my own personal profiles for the sake of screenshots.

* In both cases for Bill Murray and Nicholas Cage due to the way the corresponding API's [Placecage](https://www.placecage.com/) and [Fillmurray](https://fillmurray.com/) work you will see a lot of repetition on images of the same size, because these APIs take in width and height parameters this is inevitable. Some custom logic could be added to modify this.

* In the case of GiantBomb as there is a limited number of images the output is a bit bland and not super mixed, this can easily be updated with the inclusion of more images instead of the 10 hardcoded.

* In the case of GiantBomb you may notice one broken image. This is corresponding to the local file that is referenced - I have left this error in to emphasise as mentioned above that you need to ensure to update the chromeExtensionId to match your local version to have this work correctly.

## Possible Implementations

So the use case here is pretty basic and there are limited reasons to want to swap out all the images on a page, however if you wanted to dig dipper and experiment more there are a few other modification you could make to try improve the functionality from this basic foundation - here are some that immediately spring to mind:

* Add in a blacklisted image url list - you could create your own censorship extension
* Use the extension to write the discovered URLs on a page to a DB, might be a useful way to obtain training data for some image learning models

## Closing Thoughts

I don't get to spend a lot of time lately developing with JavaScript but I love being able to get started quickly with something fun, relatively easy and having a practical output by the end. This specific extension isn't released on the Google Chrome store however their [documentation](https://developer.chrome.com/webstore/publish) is relatively helpful and should help you publish your own extension should you wish to go down that route!

You can checkout the project & the readme with setup instructions [here](https://github.com/daniel40392/giantbomb-ify).

As always be sure to leave your feedback and thoughts below.

'Till next time!