diff --git a/src/pixie/images.nim b/src/pixie/images.nim
index b86fb1e..53b46bc 100644
--- a/src/pixie/images.nim
+++ b/src/pixie/images.nim
@@ -70,20 +70,16 @@ proc `[]=`*(image: Image, x, y: int, rgba: ColorRGBA) {.inline.} =
 
 proc fill*(image: Image, rgba: ColorRgba) =
   ## Fills the image with a solid color.
-  for y in 0 ..< image.height:
-    for x in 0 ..< image.width:
-      image.setRgbaUnsafe(x, y, rgba)
+  for c in image.data.mitems:
+    c = rgba
 
 proc invert*(image: Image) =
   ## Inverts all of the colors and alpha.
-  for y in 0 ..< image.height:
-    for x in 0 ..< image.width:
-      var rgba = image.getRgbaUnsafe(x, y)
-      rgba.r = 255 - rgba.r
-      rgba.g = 255 - rgba.g
-      rgba.b = 255 - rgba.b
-      rgba.a = 255 - rgba.a
-      image.setRgbaUnsafe(x, y, rgba)
+  for rgba in image.data.mitems:
+    rgba.r = 255 - rgba.r
+    rgba.g = 255 - rgba.g
+    rgba.b = 255 - rgba.b
+    rgba.a = 255 - rgba.a
 
 proc subImage*(image: Image, x, y, w, h: int): Image =
   ## Gets a sub image of the main image.
@@ -210,17 +206,17 @@ proc resize*(srcImage: Image, width, height: int): Image =
 
 proc blur*(image: Image, radius: float32): Image =
   ## Applies Gaussian blur to the image given a radius.
-  let radius = (radius).int
+  let radius = radius.int
   if radius == 0:
     return image.copy()
 
   # Compute lookup table for 1d Gaussian kernel.
-  var lookup = newSeq[float](radius*2+1)
+  var lookup = newSeq[float](radius * 2 + 1)
   var total = 0.0
   for xb in -radius .. radius:
     let s = radius.float32 / 2.2 # 2.2 matches Figma.
     let x = xb.float32
-    let a = 1/sqrt(2*PI*s^2) * exp(-1*x^2/(2*s^2))
+    let a = 1 / sqrt(2 * PI * s^2) * exp(-1 * x^2 / (2 * s^2))
     lookup[xb + radius] = a
     total += a
   for xb in -radius .. radius:
@@ -270,17 +266,18 @@ proc blur*(image: Image, radius: float32): Image =
 
 proc blurAlpha*(image: Image, radius: float32): Image =
   ## Applies Gaussian blur to the image given a radius.
-  let radius = (radius).int
+  let radius = radius.int
   if radius == 0:
     return image.copy()
 
   # Compute lookup table for 1d Gaussian kernel.
-  var lookup = newSeq[float](radius*2+1)
-  var total = 0.0
+  var
+    lookup = newSeq[float](radius * 2 + 1)
+    total = 0.0
   for xb in -radius .. radius:
     let s = radius.float32 / 2.2 # 2.2 matches Figma.
     let x = xb.float32
-    let a = 1/sqrt(2*PI*s^2) * exp(-1*x^2/(2*s^2))
+    let a = 1 / sqrt(2 * PI * s^2) * exp(-1 * x^2 / (2 * s^2))
     lookup[xb + radius] = a
     total += a
   for xb in -radius .. radius:
@@ -295,7 +292,7 @@ proc blurAlpha*(image: Image, radius: float32): Image =
         let c2 = image[x + xb, y]
         let a = lookup[xb + radius]
         alpha += c2.a.float32 * a
-      blurX.setRgbaUnsafe(x, y, rgba(0,0,0, (alpha).uint8))
+      blurX.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
 
   # Blur in the Y direction.
   var blurY = newImage(image.width, image.height)
@@ -306,7 +303,7 @@ proc blurAlpha*(image: Image, radius: float32): Image =
         let c2 = blurX[x, y + yb]
         let a = lookup[yb + radius]
         alpha += c2.a.float32 * a
-      blurY.setRgbaUnsafe(x, y, rgba(0,0,0, (alpha).uint8))
+      blurY.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
 
   return blurY
 
@@ -351,27 +348,23 @@ proc shadow*(
   result.fill(color)
   result.draw(shadow, blendMode = bmMask)
 
-proc applyOpacity*(image: Image, opacity: float32): Image =
+proc applyOpacity*(image: Image, opacity: float32) =
   ## Multiplies alpha of the image by opacity.
-  result = newImage(image.width, image.height)
   let op = (255 * opacity).uint32
-  for y in 0 ..< image.height:
-    for x in 0 ..< image.width:
-      var rgba = image.getRgbaUnsafe(x, y)
-      rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
-      result.setRgbaUnsafe(x, y, rgba)
+  for i in 0 ..< image.data.len:
+    var rgba = image.data[i]
+    rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
+    image.data[i] = rgba
 
-proc sharpOpacity*(image: Image): Image =
+proc sharpOpacity*(image: Image) =
   ## Sharpens the opacity to extreme.
   ## A = 0 stays 0. Anything else turns into 255.
-  result = newImage(image.width, image.height)
-  for y in 0 ..< image.height:
-    for x in 0 ..< image.width:
-      var rgba = image.getRgbaUnsafe(x, y)
-      if rgba.a == 0:
-        result.setRgbaUnsafe(x, y, rgba(0, 0, 0, 0))
-      else:
-        result.setRgbaUnsafe(x, y, rgba(255, 255, 255, 255))
+  for i in 0 ..< image.data.len:
+    var rgba = image.data[i]
+    if rgba.a == 0:
+      image.data[i] = rgba(0, 0, 0, 0)
+    else:
+      image.data[i] = rgba(255, 255, 255, 255)
 
 proc drawCorrect*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
   ## Draws one image onto another using matrix with color blending.
@@ -410,7 +403,6 @@ proc drawUberStatic(
   start, stepX, stepY: Vec2,
   lines: array[0..3, Segment],
   blendMode: static[BlendMode],
-  inPlace: static[bool],
   smooth: static[bool],
 ) =
   for y in 0 ..< a.height:
@@ -440,12 +432,6 @@ proc drawUberStatic(
     when blendMode == bmIntersectMask:
       if xMin > 0:
         zeroMem(c.getAddr(0, y), 4*xMin)
-    else:
-      when not inPlace:
-        # for x in 0 ..< xMin:
-        #   result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y))
-        if xMin > 0:
-          copyMem(c.getAddr(0, y), a.getAddr(0, y), 4*xMin)
 
     for x in xMin ..< xMax:
       let srcPos = start + stepX * float32(x) + stepY * float32(y)
@@ -464,12 +450,6 @@ proc drawUberStatic(
     when blendMode == bmIntersectMask:
       if a.width - xMax > 0:
         zeroMem(c.getAddr(xMax, y), 4*(a.width - xMax))
-    else:
-      when not inPlace:
-        # for x in xMax ..< a.width:
-        #  result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y))
-        if a.width - xMax > 0:
-          copyMem(c.getAddr(xMax, y), a.getAddr(xMax, y), 4*(a.width - xMax))
 
 proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
   ## Draws one image onto another using matrix with color blending.
@@ -511,54 +491,54 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
 
   if not smooth:
     case blendMode
-    of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true, false)
-    of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true, false)
-    of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true, false)
-    of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true, false)
-    of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true, false)
-    of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true, false)
-    of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true, false)
-    of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true, false)
-    of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true, false)
-    of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true, false)
-    of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true, false)
-    of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true, false)
-    of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true, false)
-    of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true, false)
-    of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true, false)
-    of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true, false)
-    of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true, false)
-    of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true, false)
-    of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true, false)
-    of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true, false)
-    of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true, false)
-    of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true, false)
-    of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true, false)
+    of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, false)
+    of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, false)
+    of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, false)
+    of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, false)
+    of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, false)
+    of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, false)
+    of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, false)
+    of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, false)
+    of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, false)
+    of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, false)
+    of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, false)
+    of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, false)
+    of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, false)
+    of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, false)
+    of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, false)
+    of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, false)
+    of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, false)
+    of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, false)
+    of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, false)
+    of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, false)
+    of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, false)
+    of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, false)
+    of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, false)
   else:
     case blendMode
-    of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true, true)
-    of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true, true)
-    of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true, true)
-    of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true, true)
-    of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true, true)
-    of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true, true)
-    of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true, true)
-    of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true, true)
-    of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true, true)
-    of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true, true)
-    of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true, true)
-    of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true, true)
-    of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true, true)
-    of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true, true)
-    of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true, true)
-    of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true, true)
-    of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true, true)
-    of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true, true)
-    of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true, true)
-    of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true, true)
-    of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true, true)
-    of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true, true)
-    of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true, true)
+    of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true)
+    of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true)
+    of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true)
+    of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true)
+    of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true)
+    of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true)
+    of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true)
+    of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true)
+    of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true)
+    of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true)
+    of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true)
+    of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true)
+    of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true)
+    of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true)
+    of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true)
+    of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true)
+    of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true)
+    of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true)
+    of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true)
+    of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true)
+    of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true)
+    of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true)
+    of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true)
 
 proc draw*(
   a, b: Image, pos = vec2(0, 0), blendMode = bmNormal
diff --git a/tests/benchmark_images.nim b/tests/benchmark_images.nim
new file mode 100644
index 0000000..4d6c390
--- /dev/null
+++ b/tests/benchmark_images.nim
@@ -0,0 +1,79 @@
+import chroma, pixie, fidget/opengl/perf
+
+const iterations = 100
+
+proc fillOriginal(a: Image, rgba: ColorRGBA) =
+  for y in 0 ..< a.height:
+    for x in 0 ..< a.width:
+      a.setRgbaUnsafe(x, y, rgba)
+
+proc invertOriginal(a: Image) =
+  for y in 0 ..< a.height:
+    for x in 0 ..< a.width:
+      var rgba = a.getRgbaUnsafe(x, y)
+      rgba.r = 255 - rgba.r
+      rgba.g = 255 - rgba.g
+      rgba.b = 255 - rgba.b
+      rgba.a = 255 - rgba.a
+      a.setRgbaUnsafe(x, y, rgba)
+
+proc applyOpacityOriginal(a: Image, opacity: float32): Image =
+  result = newImage(a.width, a.height)
+  let op = (255 * opacity).uint32
+  for y in 0 ..< a.height:
+    for x in 0 ..< a.width:
+      var rgba = a.getRgbaUnsafe(x, y)
+      rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
+      result.setRgbaUnsafe(x, y, rgba)
+
+proc sharpOpacityOriginal(a: Image): Image =
+  result = newImage(a.width, a.height)
+  for y in 0 ..< a.height:
+    for x in 0 ..< a.width:
+      var rgba = a.getRgbaUnsafe(x, y)
+      if rgba.a == 0:
+        result.setRgbaUnsafe(x, y, rgba(0, 0, 0, 0))
+      else:
+        result.setRgbaUnsafe(x, y, rgba(255, 255, 255, 255))
+
+timeIt "fillOriginal":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.fillOriginal(rgba(255, 255, 255, 255))
+  doAssert a[0, 0] == rgba(255, 255, 255, 255)
+
+timeIt "fill":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.fill(rgba(255, 255, 255, 255))
+  doAssert a[0, 0] == rgba(255, 255, 255, 255)
+
+timeIt "invertOriginal":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.invertOriginal()
+
+timeIt "invert":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.invert()
+
+timeIt "applyOpacityOriginal":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a = a.applyOpacityOriginal(0.5)
+
+timeIt "applyOpacity":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.applyOpacity(0.5)
+
+timeIt "sharpOpacityOriginal":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a = a.sharpOpacityOriginal()
+
+timeIt "sharpOpacity":
+  var a = newImage(2560, 1440)
+  for i in 0 ..< iterations:
+    a.sharpOpacity()
diff --git a/tests/benchmark_draw.nim b/tests/benchmark_images_draw.nim
similarity index 100%
rename from tests/benchmark_draw.nim
rename to tests/benchmark_images_draw.nim
diff --git a/tests/benchmark_shadows.nim b/tests/benchmark_images_shadows.nim
similarity index 70%
rename from tests/benchmark_shadows.nim
rename to tests/benchmark_images_shadows.nim
index adb684b..ee42cc1 100644
--- a/tests/benchmark_shadows.nim
+++ b/tests/benchmark_images_shadows.nim
@@ -4,13 +4,15 @@ timeIt "spread":
   var tmp = 0
   var spread: Image
   for i in 0 ..< 100:
-    var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
-    var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
+    var a = newImage(100, 100)
+    var b = newImage(50, 50)
+    b.fill(rgba(0, 0, 0, 255))
     a.draw(b, vec2(25, 25))
 
     spread = a.spread(spread = 10)
 
-    b = newImageFill(50, 50, rgba(255, 255, 255, 255))
+    b = newImage(50, 50)
+    b.fill(rgba(255, 255, 255, 255))
     spread.draw(b, vec2(25, 25))
 
     tmp += spread.width * spread.height
@@ -21,13 +23,15 @@ timeIt "blur":
   var tmp = 0
   var blur: Image
   for i in 0 ..< 100:
-    var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
-    var b = newImageFill(50, 50, rgba(255, 255, 255, 255))
+    var a = newImage(100, 100)
+    var b = newImage(50, 50)
+    b.fill(rgba(255, 255, 255, 255))
     a.draw(b, vec2(25, 25))
 
     blur = a.blur(radius = 10)
 
-    b = newImageFill(50, 50, rgba(255, 255, 255, 255))
+    b = newImage(50, 50)
+    b.fill(rgba(255, 255, 255, 255))
     blur.draw(b, vec2(25, 25))
 
     tmp += blur.width * blur.height
@@ -38,14 +42,16 @@ timeIt "shadow":
   var tmp = 0
   var shadow: Image
   for i in 0 ..< 100:
-    var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
-    var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
+    var a = newImage(100, 100)
+    var b = newImage(50, 50)
+    b.fill(rgba(0, 0, 0, 255))
     a.draw(b, vec2(25, 25))
 
     shadow = a.shadow(
       offset = vec2(0, 0), spread = 10, blur = 10, color = rgba(0, 0, 0, 255))
 
-    b = newImageFill(50, 50, rgba(255, 255, 255, 255))
+    b = newImage(50, 50)
+    b.fill(rgba(255, 255, 255, 255))
     shadow.draw(b, vec2(25, 25))
 
     tmp += shadow.width * shadow.height
@@ -57,8 +63,9 @@ timeIt "shadow":
 #   var tmp = 0
 #   var shadow: Image
 #   for i in 0 ..< 1:
-#     var a = newImageFill(10, 200, rgba(0, 0, 0, 0))
-#     var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
+#     var a = newImage(10, 200)
+#     var b = newImage(50, 50)
+#     b.fill(rgba(0, 0, 0, 255))
 #     a.draw(b, vec2(-25, -25))
 
 #     for spread in 0 .. 0:
@@ -73,7 +80,8 @@ timeIt "shadow":
 #         for y in 25 ..< (25 + spread + blur).int:
 #           echo y - 25, ":", shadow[5, y].a
 
-#         b = newImageFill(50, 50, rgba(255, 255, 255, 255))
+#         b = newImage(50, 50)
+#         b.fill(rgba(255, 255, 255, 255))
 #         shadow.draw(b, vec2(-25, -25))
 
 #     tmp += shadow.width * shadow.height
diff --git a/tests/benchmark_inplace.nim b/tests/benchmark_inplace.nim
deleted file mode 100644
index 6c9a641..0000000
--- a/tests/benchmark_inplace.nim
+++ /dev/null
@@ -1,209 +0,0 @@
-import pixie, chroma, vmath, fidget/opengl/perf, pixie/fileformats/bmp
-
-proc inPlaceDraw*(destImage: Image, srcImage: Image, mat: Mat3, blendMode = bmNormal) =
-  ## Draws one image onto another using matrix with color blending.
-  for y in 0 ..< destImage.width:
-    for x in 0 ..< destImage.height:
-      let srcPos = mat * vec2(x.float32, y.float32)
-      let destRgba = destImage.getRgbaUnsafe(x, y)
-      var rgba = destRgba
-      var srcRgba = rgba(0, 0, 0, 0)
-      if srcImage.inside(srcPos.x.floor.int, srcPos.y.floor.int):
-        srcRgba = srcImage.getRgbaSmooth(srcPos.x - 0.5, srcPos.y - 0.5)
-      if blendMode.hasEffect(srcRgba):
-        rgba = blendMode.mix(destRgba, srcRgba)
-      destImage.setRgbaUnsafe(x, y, rgba)
-
-proc inPlaceDraw*(destImage: Image, srcImage: Image, pos = vec2(0, 0), blendMode = bmNormal) =
-  destImage.inPlaceDraw(srcImage, translate(-pos), blendMode)
-
-proc drawStepperInPlace*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode) =
-  ## Draws one image onto another using matrix with color blending.
-
-  type Segment = object
-    ## A math segment from point "at" to point "to"
-    at*: Vec2
-    to*: Vec2
-
-  proc segment(at, to: Vec2): Segment =
-    result.at = at
-    result.to = to
-
-  proc intersects(a, b: Segment, at: var Vec2): bool =
-    ## Checks if the a segment intersects b segment.
-    ## If it returns true, at will have point of intersection
-    var s1x, s1y, s2x, s2y: float32
-    s1x = a.to.x - a.at.x
-    s1y = a.to.y - a.at.y
-    s2x = b.to.x - b.at.x
-    s2y = b.to.y - b.at.y
-
-    var s, t: float32
-    s = (-s1y * (a.at.x - b.at.x) + s1x * (a.at.y - b.at.y)) /
-        (-s2x * s1y + s1x * s2y)
-    t = (s2x * (a.at.y - b.at.y) - s2y * (a.at.x - b.at.x)) /
-        (-s2x * s1y + s1x * s2y)
-
-    if s >= 0 and s < 1 and t >= 0 and t < 1:
-      at.x = a.at.x + (t * s1x)
-      at.y = a.at.y + (t * s1y)
-      return true
-    return false
-
-  var
-    matInv = mat.inverse()
-    # compute movement vectors
-    h = 0.5.float32
-    start = matInv * vec2(0 + h, 0 + h)
-    stepX = matInv * vec2(1 + h, 0 + h) - start
-    stepY = matInv * vec2(0 + h, 1 + h) - start
-    minFilterBy2 = max(stepX.length, stepY.length)
-    b = b
-
-  let corners = [
-    mat * vec2(0, 0),
-    mat * vec2(b.width.float32, 0),
-    mat * vec2(b.width.float32, b.height.float32),
-    mat * vec2(0, b.height.float32)
-  ]
-
-  let lines = [
-    segment(corners[0], corners[1]),
-    segment(corners[1], corners[2]),
-    segment(corners[2], corners[3]),
-    segment(corners[3], corners[0])
-  ]
-
-  while minFilterBy2 > 2.0:
-    b = b.minifyBy2()
-    start /= 2
-    stepX /= 2
-    stepY /= 2
-    minFilterBy2 /= 2
-
-  template forBlend(
-    mixer: proc(a, b: ColorRGBA): ColorRGBA,
-    getRgba: proc(a: Image, x, y: float32): ColorRGBA {.inline.},
-  ) =
-    for y in 0 ..< a.height:
-      var
-        xMin = 0
-        xMax = 0
-        hasIntersection = false
-      for yOffset in [0.float32, 1]:
-        var scanLine = segment(
-          vec2(-100000, y.float32 + yOffset),
-          vec2(10000, y.float32 + yOffset)
-        )
-        for l in lines:
-          var at: Vec2
-          if intersects(l, scanLine, at):
-            if hasIntersection:
-              xMin = min(xMin, at.x.floor.int)
-              xMax = max(xMax, at.x.ceil.int)
-            else:
-              hasIntersection = true
-              xMin = at.x.floor.int
-              xMax = at.x.ceil.int
-
-      xMin = xMin.clamp(0, a.width)
-      xMax = xMax.clamp(0, a.width)
-
-      # for x in 0 ..< xMin:
-      #   result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y))
-      # if xMin > 0:
-      #   copyMem(a.getAddr(0, y), a.getAddr(0, y), 4*xMin)
-
-      for x in xMin ..< xMax:
-        let srcV = start + stepX * float32(x) + stepY * float32(y)
-        var rgba = a.getRgbaUnsafe(x, y)
-        if b.inside((srcV.x - h).int, (srcV.y - h).int):
-          let rgba2 = b.getRgba(srcV.x - h, srcV.y - h)
-          rgba = mixer(rgba, rgba2)
-        a.setRgbaUnsafe(x, y, rgba)
-
-      #for x in xMax ..< a.width:
-      #  result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y))
-      # if a.width - xMax > 0:
-      #   copyMem(result.getAddr(xMax, y), a.getAddr(xMax, y), 4*(a.width - xMax))
-
-  proc getRgba(a: Image, x, y: float32): ColorRGBA {.inline.} =
-    a.getRgbaUnsafe(x.int, y.int)
-
-  if stepX.length == 1.0 and stepY.length == 1.0:
-    case blendMode
-    of bmNormal: forBlend(blendNormal, getRgba)
-    of bmDarken: forBlend(blendDarken, getRgba)
-    of bmMultiply: forBlend(blendMultiply, getRgba)
-    of bmLinearBurn: forBlend(blendLinearBurn, getRgba)
-    of bmColorBurn: forBlend(blendColorBurn, getRgba)
-    of bmLighten: forBlend(blendLighten, getRgba)
-    of bmScreen: forBlend(blendScreen, getRgba)
-    of bmLinearDodge: forBlend(blendLinearDodge, getRgba)
-    of bmColorDodge: forBlend(blendColorDodge, getRgba)
-    of bmOverlay: forBlend(blendOverlay, getRgba)
-    of bmSoftLight: forBlend(blendSoftLight, getRgba)
-    of bmHardLight: forBlend(blendHardLight, getRgba)
-    of bmDifference: forBlend(blendDifference, getRgba)
-    of bmExclusion: forBlend(blendExclusion, getRgba)
-    of bmHue: forBlend(blendHue, getRgba)
-    of bmSaturation: forBlend(blendSaturation, getRgba)
-    of bmColor: forBlend(blendColor, getRgba)
-    of bmLuminosity: forBlend(blendLuminosity, getRgba)
-    of bmMask: forBlend(blendMask, getRgba)
-    of bmOverwrite: forBlend(blendOverwrite, getRgba)
-    of bmSubtractMask: forBlend(blendSubtractMask, getRgba)
-    of bmIntersectMask: forBlend(blendIntersectMask, getRgba)
-    of bmExcludeMask: forBlend(blendExcludeMask, getRgba)
-  else:
-    case blendMode
-    of bmNormal: forBlend(blendNormal, getRgbaSmooth)
-    of bmDarken: forBlend(blendDarken, getRgbaSmooth)
-    of bmMultiply: forBlend(blendMultiply, getRgbaSmooth)
-    of bmLinearBurn: forBlend(blendLinearBurn, getRgbaSmooth)
-    of bmColorBurn: forBlend(blendColorBurn, getRgbaSmooth)
-    of bmLighten: forBlend(blendLighten, getRgbaSmooth)
-    of bmScreen: forBlend(blendScreen, getRgbaSmooth)
-    of bmLinearDodge: forBlend(blendLinearDodge, getRgbaSmooth)
-    of bmColorDodge: forBlend(blendColorDodge, getRgbaSmooth)
-    of bmOverlay: forBlend(blendOverlay, getRgbaSmooth)
-    of bmSoftLight: forBlend(blendSoftLight, getRgbaSmooth)
-    of bmHardLight: forBlend(blendHardLight, getRgbaSmooth)
-    of bmDifference: forBlend(blendDifference, getRgbaSmooth)
-    of bmExclusion: forBlend(blendExclusion, getRgbaSmooth)
-    of bmHue: forBlend(blendHue, getRgbaSmooth)
-    of bmSaturation: forBlend(blendSaturation, getRgbaSmooth)
-    of bmColor: forBlend(blendColor, getRgbaSmooth)
-    of bmLuminosity: forBlend(blendLuminosity, getRgbaSmooth)
-    of bmMask: forBlend(blendMask, getRgbaSmooth)
-    of bmOverwrite: forBlend(blendOverwrite, getRgbaSmooth)
-    of bmSubtractMask: forBlend(blendSubtractMask, getRgbaSmooth)
-    of bmIntersectMask: forBlend(blendIntersectMask, getRgbaSmooth)
-    of bmExcludeMask: forBlend(blendExcludeMask, getRgbaSmooth)
-
-timeIt "inPlaceDraw":
-  var tmp = 0
-  for i in 0 ..< 1000:
-    var a = newImageFill(1000, 1000, rgba(0, 255, 0, 255))
-    var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
-    a.inPlaceDraw(b, pos=vec2(25, 25))
-    tmp += a.width * a.height
-  echo tmp
-
-timeIt "drawStepper":
-  var tmp = 0
-  for i in 0 ..< 1000:
-    var a = newImageFill(1000, 1000, rgba(255, 0, 0, 255))
-    var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
-    var c = a.drawStepper(b, translate(vec2(25, 25)), bmNormal)
-    tmp += c.width * c.height
-  echo tmp
-
-timeIt "drawStepperInPlace":
-  var tmp = 0
-  for i in 0 ..< 1000:
-    var a = newImageFill(1000, 1000, rgba(0, 255, 0, 255))
-    var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
-    drawStepperInPlace(a, b, translate(vec2(25, 25)), bmNormal)
-    tmp += a.width * a.height
-  echo tmp
diff --git a/tests/images/blur1.png b/tests/images/blur1.png
index 469632a..c129e3b 100644
Binary files a/tests/images/blur1.png and b/tests/images/blur1.png differ
diff --git a/tests/images/shadow1.png b/tests/images/shadow1.png
index 62ac574..3ae66d5 100644
Binary files a/tests/images/shadow1.png and b/tests/images/shadow1.png differ
diff --git a/tests/images/spread1.png b/tests/images/spread1.png
index 24b105a..3522111 100644
Binary files a/tests/images/spread1.png and b/tests/images/spread1.png differ