diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 47989c2..07ef718 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -20,7 +20,7 @@ Create a feature branch and start improving:
 % git checkout -b my-feature-branch
 ```
 
-HEAD-based development is prefered, which means all changes are applied
+HEAD-based development is preferred, which means all changes are applied
 directly on top of master.
 
 ### Step 3: Commit
diff --git a/README.md b/README.md
index 0242478..cce3c1c 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Selenium Shutterbug is a utility library written in Java for making screenshots
 
 ## Code Example
 
-Screenhot of the page with scrolling (for Chrome to make screenshot of the whole page but not viewport only):
+Screenshot of the page with scrolling (for Chrome to make screenshot of the whole page but not viewport only):
 ```
 Shutterbug.shootPage(driver, ScrollStrategy.BOTH_DIRECTIONS).save("C:\\testing\\screenshots\\");
 ```
diff --git a/pom.xml b/pom.xml
index c444585..a91e6bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,11 @@
             <artifactId>commons-io</artifactId>
             <version>2.6</version>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.8</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java
index 1e343bb..0687d79 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/core/ElementSnapshot.java
@@ -9,7 +9,6 @@
 import com.assertthat.selenium_shutterbug.utils.web.Coordinates;
 import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException;
 import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.WebElement;
 
 import java.awt.image.BufferedImage;
 import java.awt.image.RasterFormatException;
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java
index be8e3b6..f291712 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/core/PageSnapshot.java
@@ -5,9 +5,9 @@
 
 package com.assertthat.selenium_shutterbug.core;
 
-import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException;
 import com.assertthat.selenium_shutterbug.utils.image.ImageProcessor;
 import com.assertthat.selenium_shutterbug.utils.web.Coordinates;
+import com.assertthat.selenium_shutterbug.utils.web.ElementOutsideViewportException;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java b/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java
index 81de24c..0479533 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/core/Snapshot.java
@@ -69,7 +69,7 @@ public T withTitle(String title) {
      * @return instance of type Snapshot
      */
     public T withThumbnail(String path, String name, double scale) {
-        File thumbnailFile = new File(path.toString(), name);
+        File thumbnailFile = new File(path, name);
         if(!Files.exists(Paths.get(path))) {
             thumbnailFile.mkdirs();
         }
@@ -90,15 +90,12 @@ public T withThumbnail(String path, String name, double scale) {
      * @return instance of type Snapshot
      */
     public T withCroppedThumbnail(String path, String name, double scale,  double cropWidth, double cropHeight) {
-        File thumbnailFile = new File(path.toString(), name);
-        if(!Files.exists(Paths.get(path))) {
-            thumbnailFile.mkdirs();
-        }
+        File thumbnailFile = getFile(path, name);
         thumbnailImage=ImageProcessor.cropAndScale(image,scale, cropWidth, cropHeight);
         FileUtil.writeImage(thumbnailImage, EXTENSION, thumbnailFile);
         return self();
     }
-    
+
     /**
      * Generate cropped thumbnail of the original screenshot.
      * Will save different thumbnails depends on when it was called in the chain.
@@ -111,15 +108,27 @@ public T withCroppedThumbnail(String path, String name, double scale,  double cr
      * @return instance of type Snapshot
      */
     public T withCroppedThumbnail(String path, String name, double scale,  int maxWidth, int maxHeight) {
-        File thumbnailFile = new File(path.toString(), name);
-        if(!Files.exists(Paths.get(path))) {
-            thumbnailFile.mkdirs();
-        }
+        File thumbnailFile = getFile(path, name);
         thumbnailImage=ImageProcessor.cropAndScale(image,scale, maxWidth, maxHeight);
         FileUtil.writeImage(thumbnailImage, EXTENSION, thumbnailFile);
         return self();
     }
-    
+
+    /**
+     * Generate file for cropped thumbnail of the original screenshot.
+     *
+     * @param path to save thumbnail image to
+     * @param name of the resulting image
+     * @return instance of type File
+     */
+    private File getFile(String path, String name) {
+        File thumbnailFile = new File(path, name);
+        if (!Files.exists(Paths.get(path))) {
+            thumbnailFile.mkdirs();
+        }
+        return thumbnailFile;
+    }
+
     /**
      * Generate cropped thumbnail of the original screenshot.
      * Will save different thumbnails depends on when it was called in the chain.
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java
index 024a465..320b11b 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/FileUtil.java
@@ -24,7 +24,7 @@ public static String getJsScript(String filePath) {
         try {
             InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
             if (is == null) {
-                // This is needed to load the files in an OSGI enviroment when enclosed in a bundle
+                // This is needed to load the files in an OSGI environment when enclosed in a bundle
                 is = FileUtil.class.getClassLoader().getResourceAsStream(filePath);
             }
             // if the input stream is still null, this will avoid a non descriptive null pointer exception
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java
index dd7a7cc..9faeca0 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/file/UnableSaveSnapshotException.java
@@ -5,8 +5,6 @@
 
 package com.assertthat.selenium_shutterbug.utils.file;
 
-import org.openqa.selenium.WebDriverException;
-
 /**
  * Created by Glib_Briia on 17/06/2016.
  */
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java
index 19ca528..35656fc 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessor.java
@@ -5,13 +5,18 @@
 
 package com.assertthat.selenium_shutterbug.utils.image;
 
-import com.assertthat.selenium_shutterbug.utils.file.FileUtil;
+import com.assertthat.selenium_shutterbug.utils.image.model.ImageData;
 import com.assertthat.selenium_shutterbug.utils.web.Coordinates;
 
 import java.awt.*;
 import java.awt.color.ColorSpace;
-import java.awt.image.*;
-import java.io.File;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.ColorModel;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.awt.image.PixelGrabber;
 
 /**
  * Created by Glib_Briia on 17/06/2016.
@@ -19,7 +24,7 @@
 public class ImageProcessor {
 
     private static final int ARCH_SIZE = 10;
-    private static float[] matrix = new float[49];
+    private static final float[] matrix = new float[49];
     private static double pixelError = Double.MAX_VALUE;
 
     static {
@@ -57,27 +62,21 @@ public static BufferedImage getElement(BufferedImage sourceImage, Coordinates co
 
     public static BufferedImage blurArea(BufferedImage sourceImage, Coordinates coords) {
         BufferedImage blurredImage = blur(sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight()));
-        BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
-        Graphics2D g = combined.createGraphics();
-        g.drawImage(sourceImage, 0, 0, null);
-        g.drawImage(blurredImage, coords.getX(), coords.getY(), null);
-        g.dispose();
-        return combined;
+        return getBufferedImage(sourceImage, coords, blurredImage, sourceImage);
     }
 
     public static BufferedImage monochromeArea(BufferedImage sourceImage, Coordinates coords) {
         BufferedImage monochromedImage = convertToGrayAndWhite(sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight()));
-        BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
-        Graphics2D g = combined.createGraphics();
-        g.drawImage(sourceImage, 0, 0, null);
-        g.drawImage(monochromedImage, coords.getX(), coords.getY(), null);
-        g.dispose();
-        return combined;
+        return getBufferedImage(sourceImage, coords, monochromedImage, sourceImage);
     }
 
     public static BufferedImage blurExceptArea(BufferedImage sourceImage, Coordinates coords) {
         BufferedImage subImage = sourceImage.getSubimage(coords.getX(), coords.getY(), coords.getWidth(), coords.getHeight());
         BufferedImage blurredImage = blur(sourceImage);
+        return getBufferedImage(sourceImage, coords, subImage, blurredImage);
+    }
+
+    private static BufferedImage getBufferedImage(BufferedImage sourceImage, Coordinates coords, BufferedImage subImage, BufferedImage blurredImage) {
         BufferedImage combined = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = combined.createGraphics();
         g.drawImage(blurredImage, 0, 0, null);
@@ -87,8 +86,7 @@ public static BufferedImage blurExceptArea(BufferedImage sourceImage, Coordinate
     }
 
     public static BufferedImage cropAround(BufferedImage sourceImage, Coordinates coords, int offsetX, int offsetY) {
-        BufferedImage subImage = sourceImage.getSubimage(coords.getX()-offsetX, coords.getY()-offsetY, coords.getWidth()+offsetX*2, coords.getHeight()+offsetY*2);
-        return subImage;
+        return sourceImage.getSubimage(coords.getX() - offsetX, coords.getY() - offsetY, coords.getWidth() + offsetX * 2, coords.getHeight() + offsetY * 2);
     }
 
     public static BufferedImage addTitle(BufferedImage sourceImage, String title, Color color, Font textFont) {
@@ -108,156 +106,99 @@ public static BufferedImage convertToGrayAndWhite(BufferedImage sourceImage) {
     }
 
     public static boolean imagesAreEquals(BufferedImage image1, BufferedImage image2, double deviation) {
-        int width1 = image1.getWidth(null);
-        int width2 = image2.getWidth(null);
-        int height1 = image1.getHeight(null);
-        int height2 = image2.getHeight(null);
-        if ((width1 != width2) || (height1 != height2)) {
-            throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + width1 + "x" + height1 + "; image2 - " + width2 + "x" + height2);
+        ImageData image1Data = new ImageData(image1);
+        ImageData image2Data = new ImageData(image2);
+        if (image1Data.notEqualsDimensions(image2Data)) {
+            throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + image1Data.getWidth() + "x" + image1Data.getHeight() + "; image2 - " + image2Data.getWidth() + "x" + image2Data.getHeight());
         }
-        long diff = 0;
-        for (int y = 0; y < height1; y++) {
-            for (int x = 0; x < width1; x++) {
-                int rgb1 = image1.getRGB(x, y);
-                int rgb2 = image2.getRGB(x, y);
-                int r1 = (rgb1 >> 16) & 0xff;
-                int g1 = (rgb1 >> 8) & 0xff;
-                int b1 = (rgb1) & 0xff;
-                int r2 = (rgb2 >> 16) & 0xff;
-                int g2 = (rgb2 >> 8) & 0xff;
-                int b2 = (rgb2) & 0xff;
-                diff += Math.abs(r1 - r2);
-                diff += Math.abs(g1 - g2);
-                diff += Math.abs(b1 - b2);
-            }
-        }
-        double n = width1 * height1 * 3;
-        double p = diff / n / 255.0;
-        return p == 0 || p <= deviation;
+        return image1Data.equalsEachPixels(image2Data, deviation);
     }
 
     /**
      * Extends the functionality of imagesAreEqualsWithDiff, but creates a third BufferedImage and applies pixel manipulation to it.
-     * @param image1 The first image to compare
-     * @param image2 The second image to compare
+     *
+     * @param image1       The first image to compare
+     * @param image2       The second image to compare
      * @param pathFileName The output path filename for the third image, if null then is ignored
-     * @param deviation The upper limit of the pixel deviation for the test
+     * @param deviation    The upper limit of the pixel deviation for the test
      * @return If the test passes
      */
     public static boolean imagesAreEqualsWithDiff(BufferedImage image1, BufferedImage image2, String pathFileName, double deviation) {
-        BufferedImage output = new BufferedImage(image1.getWidth(), image1.getHeight(), BufferedImage.TYPE_INT_RGB);
-
-        int width1 = image1.getWidth(null);
-        int width2 = image2.getWidth(null);
-        int height1 = image1.getHeight(null);
-        int height2 = image2.getHeight(null);
-        if ((width1 != width2) || (height1 != height2)) {
-            throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + width1 + "x" + height1 + "; image2 - " + width2 + "x" + height2);
+        ImageData image1Data = new ImageData(image1);
+        ImageData image2Data = new ImageData(image2);
+        if (image1Data.notEqualsDimensions(image2Data)) {
+            throw new UnableToCompareImagesException("Images dimensions mismatch: image1 - " + image1Data.getWidth() + "x" + image1Data.getHeight() + "; image2 - " + image2Data.getWidth() + "x" + image2Data.getHeight());
         }
-        long diff = 0;
-        long recordedDiff = 0; // Records the difference so it can be compared, saves having to do three if statements
-        for (int y = 0; y < height1; y++) {
-            for (int x = 0; x < width1; x++) {
-                recordedDiff = diff;
-
-                // Grab RGB values of both images, then bit shift and bitwise AND to break them down into R, G and B
-                int rgb1 = image1.getRGB(x, y);
-                int rgb2 = image2.getRGB(x, y);
-                int r1 = (rgb1 >> 16) & 0xff;
-                int g1 = (rgb1 >> 8) & 0xff;
-                int b1 = (rgb1) & 0xff;
-                int r2 = (rgb2 >> 16) & 0xff;
-                int g2 = (rgb2 >> 8) & 0xff;
-                int b2 = (rgb2) & 0xff;
-                diff += Math.abs(r1 - r2);
-                diff += Math.abs(g1 - g2);
-                diff += Math.abs(b1 - b2);
-
-                // If difference > recorded difference, change pixel to red. If zero, set to image 1's original pixel
-                if(diff > recordedDiff)
-                    output.setRGB(x,y,new Color(255,0,0).getRGB() & rgb1); // Dark red = original position, Light red is moved to
-                else
-                    output.setRGB(x,y,rgb1);
-            }
-        }
-        int colourSpaceBytes = 3; // RGB is 24 bit, or 3 bytes
-        double totalPixels = width1 * height1 * colourSpaceBytes;
-        pixelError = diff / totalPixels / 255.0;
-
-        // Write the image as png, with the filename based on the path provided
-        if(pixelError > 0)
-            FileUtil.writeImage(output,"png",new File(pathFileName+".png"));
-        return pixelError == 0 || pixelError <= deviation;
+        return image1Data.equalsEachPixelsWithCreateDifferencesImage(image2Data, deviation, pathFileName);
     }
 
     public static BufferedImage scale(BufferedImage source, double ratio) {
-        return cropAndScale(source, ratio, 1.0,1.0);
+        return cropAndScale(source, ratio, 1.0, 1.0);
     }
-    
-    public static BufferedImage cropAndScale(BufferedImage source,double ratio, double cropWidth, double cropHeight) {
+
+    public static BufferedImage cropAndScale(BufferedImage source, double ratio, double cropWidth, double cropHeight) {
         int w = (int) (source.getWidth() * ratio);
         int h = (int) (source.getHeight() * ratio);
-        BufferedImage scaledImage = getCompatibleImage(w, h, source);
-        Graphics2D resultGraphics = scaledImage.createGraphics();
-        resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-        resultGraphics.drawImage(source, 0, 0, w, h, null);
-        resultGraphics.dispose();
-        return scaledImage.getSubimage(0, 0, (int)(w*cropWidth),(int)(h*cropHeight));
+        BufferedImage scaledImage = createAndDrawImage(source, w, h);
+        return scaledImage.getSubimage(0, 0, (int) (w * cropWidth), (int) (h * cropHeight));
     }
-    
-    public static BufferedImage cropAndScale(BufferedImage source,double ratio, int maxWidth, int maxHeight) {
+
+    public static BufferedImage cropAndScale(BufferedImage source, double ratio, int maxWidth, int maxHeight) {
         int w = (int) (source.getWidth() * ratio);
         int h = (int) (source.getHeight() * ratio);
+        BufferedImage scaledImage = createAndDrawImage(source, w, h);
+        if (maxWidth != -1 && w > maxWidth) {
+            w = maxWidth;
+        }
+        if (maxHeight != -1 && h > maxHeight) {
+            h = maxHeight;
+        }
+        return scaledImage.getSubimage(0, 0, w, h);
+    }
+
+    private static BufferedImage createAndDrawImage(BufferedImage source, int w, int h) {
         BufferedImage scaledImage = getCompatibleImage(w, h, source);
         Graphics2D resultGraphics = scaledImage.createGraphics();
         resultGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                 RenderingHints.VALUE_INTERPOLATION_BICUBIC);
         resultGraphics.drawImage(source, 0, 0, w, h, null);
         resultGraphics.dispose();
-        if(maxWidth != -1 && w > maxWidth){
-            w = maxWidth;
-        }
-        if(maxHeight != -1 && h > maxHeight){
-            h = maxHeight;
-        }
-        return scaledImage.getSubimage(0, 0, w,h);
+        return scaledImage;
     }
-    
-    
+
     private static BufferedImage getCompatibleImage(int w, int h, BufferedImage source) {
-        BufferedImage bimage = null;
-        try{
+        BufferedImage bImage = null;
+        try {
             GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
             GraphicsDevice gd = ge.getDefaultScreenDevice();
             GraphicsConfiguration gc = gd.getDefaultConfiguration();
-            bimage = gc.createCompatibleImage(w,h);
+            bImage = gc.createCompatibleImage(w, h);
         } catch (HeadlessException e) {
             // The system does not have a screen
         }
-        if (bimage == null) {
+        if (bImage == null) {
             boolean hasAlpha = hasAlpha(source);
             int type = BufferedImage.TYPE_INT_RGB;
             if (hasAlpha) {
                 type = BufferedImage.TYPE_INT_ARGB;
             }
-            bimage = new BufferedImage(w, h, type);
+            bImage = new BufferedImage(w, h, type);
         }
-        return bimage;
+        return bImage;
     }
 
     public static boolean hasAlpha(Image image) {
         // If buffered image, the color model is readily available
         if (image instanceof BufferedImage) {
-            BufferedImage bimage = (BufferedImage)image;
-            return bimage.getColorModel().hasAlpha();
+            BufferedImage bImage = (BufferedImage) image;
+            return bImage.getColorModel().hasAlpha();
         }
         // Use a pixel grabber to retrieve the image's color model;
         // grabbing a single pixel is usually sufficient
         PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
         try {
             pg.grabPixels();
-        } catch (InterruptedException e) {
+        } catch (InterruptedException ignored) {
         }
         // Get the image's color model
         ColorModel cm = pg.getColorModel();
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java
index 204ab54..490f520 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/UnableToCompareImagesException.java
@@ -9,6 +9,7 @@
  * Created by Glib_Briia on 25/06/2016.
  */
 public class UnableToCompareImagesException extends RuntimeException {
+
     public UnableToCompareImagesException() {
         super();
     }
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java
new file mode 100644
index 0000000..211f914
--- /dev/null
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/image/model/ImageData.java
@@ -0,0 +1,90 @@
+package com.assertthat.selenium_shutterbug.utils.image.model;
+
+import com.assertthat.selenium_shutterbug.utils.file.FileUtil;
+import lombok.Getter;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+
+@Getter
+public class ImageData {
+    private final int RED_RGB = new Color(255, 0, 0).getRGB();
+    private final BufferedImage image;
+    private final int width;
+    private final int height;
+
+    public ImageData(BufferedImage image) {
+        this.image = image;
+        this.width = image.getWidth(null);
+        this.height = image.getHeight(null);
+    }
+
+    public boolean notEqualsDimensions(ImageData imageData) {
+        return !equalsDimensions(imageData);
+    }
+
+    private boolean equalsDimensions(ImageData imageData) {
+        return this.width == imageData.width && this.height == imageData.height;
+    }
+
+    public boolean equalsEachPixelsWithCreateDifferencesImage(ImageData imageData, double deviation, String pathDifferenceImageFileName) {
+        return equalsEachPixelsWithCreateDifferencesImage(imageData.getImage(), deviation, pathDifferenceImageFileName);
+    }
+
+    private boolean equalsEachPixelsWithCreateDifferencesImage(BufferedImage image, double deviation, String pathDifferenceImageFileName) {
+        createDifferencesImage(image, pathDifferenceImageFileName);
+        return equalsEachPixels(image, deviation);
+    }
+
+    private void createDifferencesImage(BufferedImage image, String pathDifferenceImageFileName) {
+        BufferedImage output = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+                int rgb1 = this.getImage().getRGB(x, y);
+                int rgb2 = image.getRGB(x, y);
+
+                // If difference > recorded difference, change pixel to red. If zero, set to image 1's original pixel
+                if (rgb1 != rgb2)
+                    output.setRGB(x, y, RED_RGB & rgb1); // Dark red = original position, Light red is moved to
+                else
+                    output.setRGB(x, y, rgb1);
+            }
+        }
+
+        FileUtil.writeImage(output, "png", new File(pathDifferenceImageFileName + ".png"));
+    }
+
+    public boolean equalsEachPixels(ImageData imageData, double deviation) {
+        return equalsEachPixels(imageData.getImage(), deviation);
+    }
+
+    private boolean equalsEachPixels(BufferedImage image, double deviation) {
+        double p = calculatePixelsDifference(image);
+
+        return p == 0 || p <= deviation;
+    }
+
+    private double calculatePixelsDifference(BufferedImage image) {
+        long diff = 0;
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+                int rgb1 = this.getImage().getRGB(x, y);
+                int rgb2 = image.getRGB(x, y);
+                int r1 = (rgb1 >> 16) & 0xff;
+                int g1 = (rgb1 >> 8) & 0xff;
+                int b1 = (rgb1) & 0xff;
+                int r2 = (rgb2 >> 16) & 0xff;
+                int g2 = (rgb2 >> 8) & 0xff;
+                int b2 = (rgb2) & 0xff;
+                diff += Math.abs(r1 - r2);
+                diff += Math.abs(g1 - g2);
+                diff += Math.abs(b1 - b2);
+            }
+        }
+        double n = width * height * 3;
+
+        return diff / n / 255.0;
+    }
+}
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java
index 2b8289b..21b2634 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Browser.java
@@ -8,8 +8,12 @@
 import com.assertthat.selenium_shutterbug.utils.file.FileUtil;
 import com.google.common.collect.ImmutableMap;
 import org.openqa.selenium.Dimension;
-import org.openqa.selenium.*;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.OutputType;
 import org.openqa.selenium.Point;
+import org.openqa.selenium.TakesScreenshot;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
 import org.openqa.selenium.chrome.ChromeDriver;
 import org.openqa.selenium.remote.CommandInfo;
 import org.openqa.selenium.remote.HttpCommandExecutor;
@@ -35,17 +39,17 @@
  */
 public class Browser {
 
-    public static final String RELATIVE_COORDS_JS = "js/relative-element-coords.js";
-    public static final String MAX_DOC_WIDTH_JS = "js/max-document-width.js";
-    public static final String MAX_DOC_HEIGHT_JS = "js/max-document-height.js";
-    public static final String VIEWPORT_HEIGHT_JS = "js/viewport-height.js";
-    public static final String VIEWPORT_WIDTH_JS = "js/viewport-width.js";
-    public static final String SCROLL_TO_JS = "js/scroll-to.js";
-    public static final String SCROLL_INTO_VIEW_JS = "js/scroll-element-into-view.js";
-    public static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js";
-    public static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js";
-    public static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js";
-    public static final String ALL_METRICS = "js/all-metrics.js";
+    private static final String RELATIVE_COORDS_JS = "js/relative-element-coords.js";
+    private static final String MAX_DOC_WIDTH_JS = "js/max-document-width.js";
+    private static final String MAX_DOC_HEIGHT_JS = "js/max-document-height.js";
+    private static final String VIEWPORT_HEIGHT_JS = "js/viewport-height.js";
+    private static final String VIEWPORT_WIDTH_JS = "js/viewport-width.js";
+    private static final String SCROLL_TO_JS = "js/scroll-to.js";
+    private static final String SCROLL_INTO_VIEW_JS = "js/scroll-element-into-view.js";
+    private static final String CURRENT_SCROLL_Y_JS = "js/get-current-scrollY.js";
+    private static final String CURRENT_SCROLL_X_JS = "js/get-current-scrollX.js";
+    private static final String DEVICE_PIXEL_RATIO = "js/get-device-pixel-ratio.js";
+    private static final String ALL_METRICS = "js/all-metrics.js";
 
     private WebDriver driver;
     private int docHeight = -1;
@@ -57,9 +61,9 @@ public class Browser {
 
     public Browser(WebDriver driver, boolean useDevicePixelRatio) {
         this.driver = driver;
-        if(useDevicePixelRatio) {
+        if (useDevicePixelRatio) {
             Object devicePixelRatio = executeJsScript(DEVICE_PIXEL_RATIO);
-            this.devicePixelRatio = devicePixelRatio instanceof Double? (Double)devicePixelRatio: (Long)devicePixelRatio*1.0;
+            this.devicePixelRatio = devicePixelRatio instanceof Double ? (Double) devicePixelRatio : (Long) devicePixelRatio * 1.0;
         }
     }
 
@@ -67,15 +71,15 @@ public Double getDevicePixelRatio() {
         return devicePixelRatio;
     }
 
-    public static void wait(int milis) {
+    public static void wait(int ms) {
         try {
-            Thread.sleep(milis);
+            Thread.sleep(ms);
         } catch (InterruptedException e) {
             throw new UnableTakeSnapshotException(e);
         }
     }
 
-    public void setScrollTimeout(int scrollTimeout){
+    public void setScrollTimeout(int scrollTimeout) {
         this.scrollTimeout = scrollTimeout;
     }
 
@@ -86,19 +90,21 @@ public BufferedImage takeScreenshot() {
         } catch (IOException e) {
             throw new UnableTakeSnapshotException(e);
         } finally {
-	    // add this to clean up leaving this file in the temporary directory forever...
-	    if (srcFile.exists()) {
-	       srcFile.delete();
-	    }
-	}
+            // add this to clean up leaving this file in the temporary directory forever...
+            if (srcFile.exists()) {
+                srcFile.delete();
+            }
+        }
 
     }
 
-    /**Using different screenshot strategy dependently on driver:
+    /**
+     * Using different screenshot strategy dependently on driver:
      * for  chrome - chrome command will be used
      * for others - their default screenshot methods
+     *
      * @return BufferedImage resulting image
-     * */
+     */
     public BufferedImage takeScreenshotEntirePage() {
         if (driver instanceof EventFiringWebDriver) {
             driver = ((EventFiringWebDriver) this.driver).getWrappedDriver();
@@ -116,20 +122,20 @@ public BufferedImage takeScreenshotEntirePage() {
 
     public BufferedImage takeScreenshotEntirePageDefault() {
         final int _docWidth = this.getDocWidth();
-		final int _docHeight = this.getDocHeight();
-		BufferedImage combinedImage = new BufferedImage(_docWidth, _docHeight, BufferedImage.TYPE_INT_ARGB);
+        final int _docHeight = this.getDocHeight();
+        BufferedImage combinedImage = new BufferedImage(_docWidth, _docHeight, BufferedImage.TYPE_INT_ARGB);
         Graphics2D g = combinedImage.createGraphics();
         int _viewportWidth = this.getViewportWidth();
         int _viewportHeight = this.getViewportHeight();
         final int scrollBarMaxWidth = 40; // this is probably too high, but better to be safe than sorry
 
-		if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth))
-        	_viewportHeight-=scrollBarMaxWidth; // some space for a scrollbar
+        if (_viewportWidth < _docWidth || (_viewportHeight < _docHeight && _viewportWidth - scrollBarMaxWidth < _docWidth))
+            _viewportHeight -= scrollBarMaxWidth; // some space for a scrollbar // TODO viewportHeight and scrollVarMaxWidth?
         if (_viewportHeight < _docHeight)
-        	_viewportWidth-=scrollBarMaxWidth; // some space for a scrollbar
+            _viewportWidth -= scrollBarMaxWidth; // some space for a scrollbar
 
-		int horizontalIterations = (int) Math.ceil(((double) _docWidth) / _viewportWidth);
-		int verticalIterations = (int) Math.ceil(((double) _docHeight) / _viewportHeight);
+        int horizontalIterations = (int) Math.ceil(((double) _docWidth) / _viewportWidth);
+        int verticalIterations = (int) Math.ceil(((double) _docHeight) / _viewportHeight);
         outer_loop:
         for (int j = 0; j < verticalIterations; j++) {
             this.scrollTo(0, j * _viewportHeight);
@@ -138,7 +144,7 @@ public BufferedImage takeScreenshotEntirePageDefault() {
                 wait(scrollTimeout);
                 Image image = takeScreenshot();
                 g.drawImage(image, this.getCurrentScrollX(), this.getCurrentScrollY(), null);
-                if(_docWidth == image.getWidth(null) && _docHeight == image.getHeight(null)){
+                if (_docWidth == image.getWidth(null) && _docHeight == image.getHeight(null)) {
                     break outer_loop;
                 }
             }
@@ -150,7 +156,7 @@ public BufferedImage takeScreenshotEntirePageDefault() {
     public BufferedImage takeScreenshotEntirePageUsingChromeCommand() {
         //should use devicePixelRatio by default as chrome command executor makes screenshot account for that
         Object devicePixelRatio = executeJsScript(DEVICE_PIXEL_RATIO);
-        this.devicePixelRatio = devicePixelRatio instanceof Double? (Double)devicePixelRatio: (Long)devicePixelRatio*1.0;
+        this.devicePixelRatio = devicePixelRatio instanceof Double ? (Double) devicePixelRatio : (Long) devicePixelRatio * 1.0;
 
         try {
             CommandInfo cmd = new CommandInfo("/session/:sessionId/chromium/send_command_and_get_result", HttpMethod.POST);
@@ -186,31 +192,36 @@ public WebDriver getUnderlyingDriver() {
     }
 
     public int getCurrentScrollX() {
-        return (int)(((Long) executeJsScript(Browser.CURRENT_SCROLL_X_JS))*devicePixelRatio);
+        return (int) (((Long) executeJsScript(Browser.CURRENT_SCROLL_X_JS)) * devicePixelRatio);
     }
 
     public int getCurrentScrollY() {
-        return (int)(((Long) executeJsScript(Browser.CURRENT_SCROLL_Y_JS))*devicePixelRatio);
+        return (int) (((Long) executeJsScript(Browser.CURRENT_SCROLL_Y_JS)) * devicePixelRatio);
     }
 
     public int getDocWidth() {
-        return docWidth != -1 ? docWidth : (int)(((Long) executeJsScript(MAX_DOC_WIDTH_JS))*devicePixelRatio);
+        if (docWidth == -1) docWidth = (int) (((Long) executeJsScript(MAX_DOC_WIDTH_JS)) * devicePixelRatio);
+        return docWidth;
     }
 
     public int getDocHeight() {
-        return docHeight != -1 ? docHeight : (int)(((Long) executeJsScript(MAX_DOC_HEIGHT_JS))*devicePixelRatio);
+        if (docHeight == -1) docHeight = (int) (((Long) executeJsScript(MAX_DOC_HEIGHT_JS)) * devicePixelRatio);
+        return docHeight;
     }
 
     public int getViewportWidth() {
-        return viewportWidth != -1 ? viewportWidth : (int)(((Long) executeJsScript(VIEWPORT_WIDTH_JS))*devicePixelRatio);
+        if (viewportWidth == -1) viewportWidth = (int) (((Long) executeJsScript(VIEWPORT_WIDTH_JS)) * devicePixelRatio);
+        return viewportWidth;
     }
 
     public int getViewportHeight() {
-        return viewportHeight != -1 ? viewportHeight : (int)(((Long) executeJsScript(VIEWPORT_HEIGHT_JS)).intValue()*devicePixelRatio);
+        if (viewportHeight == -1)
+            viewportHeight = (int) (((Long) executeJsScript(VIEWPORT_HEIGHT_JS)) * devicePixelRatio);
+        return viewportHeight;
     }
 
     public Coordinates getBoundingClientRect(WebElement element) {
-        String script = FileUtil.getJsScript(RELATIVE_COORDS_JS);
+        FileUtil.getJsScript(RELATIVE_COORDS_JS);
         ArrayList<String> list = (ArrayList<String>) executeJsScript(RELATIVE_COORDS_JS, element);
         Point start = new Point(Integer.parseInt(list.get(0)), Integer.parseInt(list.get(1)));
         Dimension size = new Dimension(Integer.parseInt(list.get(2)), Integer.parseInt(list.get(3)));
@@ -222,7 +233,7 @@ public void scrollToElement(WebElement element) {
     }
 
     public void scrollTo(int x, int y) {
-        executeJsScript(SCROLL_TO_JS, x/devicePixelRatio, y/devicePixelRatio);
+        executeJsScript(SCROLL_TO_JS, x / devicePixelRatio, y / devicePixelRatio);
     }
 
     public Object executeJsScript(String filePath, Object... arg) {
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java
index 5d17f9b..1295e32 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/Coordinates.java
@@ -14,10 +14,10 @@
  */
 public class Coordinates {
 
-    private int width;
-    private int height;
-    private int x;
-    private int y;
+    private final int width;
+    private final int height;
+    private final int x;
+    private final int y;
 
     public Coordinates(WebElement element, Double devicePixelRatio) {
         Point point = element.getLocation();
diff --git a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java
index e980f99..82b05c7 100644
--- a/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java
+++ b/src/main/java/com/assertthat/selenium_shutterbug/utils/web/ElementOutsideViewportException.java
@@ -4,6 +4,7 @@
  * Created by Glib_Briia on 10/07/2016.
  */
 public class ElementOutsideViewportException extends RuntimeException  {
+
     public ElementOutsideViewportException() {
         super();
     }
diff --git a/src/main/resources/js/all-metrics.js b/src/main/resources/js/all-metrics.js
index f0ddafe..e9c87b4 100644
--- a/src/main/resources/js/all-metrics.js
+++ b/src/main/resources/js/all-metrics.js
@@ -1,3 +1,5 @@
-({width: Math.max(window.innerWidth,document.body.scrollWidth,document.documentElement.scrollWidth)|0,
-height: Math.max(window.innerHeight,document.body.scrollHeight,document.documentElement.scrollHeight)|0,
-deviceScaleFactor: window.devicePixelRatio || 1,mobile: typeof window.orientation !== 'undefined'})
+({
+    width: Math.max(window.innerWidth, document.body.scrollWidth, document.documentElement.scrollWidth) | 0,
+    height: Math.max(window.innerHeight, document.body.scrollHeight, document.documentElement.scrollHeight) | 0,
+    deviceScaleFactor: window.devicePixelRatio || 1, mobile: typeof window.orientation !== 'undefined'
+});
diff --git a/src/main/resources/js/relative-element-coords.js b/src/main/resources/js/relative-element-coords.js
index 42770d8..67d74f2 100644
--- a/src/main/resources/js/relative-element-coords.js
+++ b/src/main/resources/js/relative-element-coords.js
@@ -1,2 +1,2 @@
-var rect =  arguments[0].getBoundingClientRect();
-return [ '' + parseInt(rect.left), '' + parseInt(rect.top), '' + parseInt(rect.width), '' + parseInt(rect.height) ]
\ No newline at end of file
+var rect = arguments[0].getBoundingClientRect();
+return ['' + parseInt(rect.left), '' + parseInt(rect.top), '' + parseInt(rect.width), '' + parseInt(rect.height)];
\ No newline at end of file
diff --git a/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java b/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java
index 9f46121..5515f3e 100644
--- a/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java
+++ b/src/test/java/com/assertthat/selenium_shutterbug/utils/image/ImageProcessorTest.java
@@ -19,7 +19,6 @@
 import com.assertthat.selenium_shutterbug.utils.web.Coordinates;
 import org.junit.Ignore;
 import org.junit.Test;
-import org.openqa.selenium.*;
 import org.openqa.selenium.Dimension;
 import org.openqa.selenium.Point;
 
@@ -28,7 +27,7 @@
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Created by Glib_Briia, Inha Briia on 26/06/2016.
