From a95d1f546bb3e95547247bd9aebc7f2688def90b Mon Sep 17 00:00:00 2001
From: Ryan Oldenburg <ryan@guzba.com>
Date: Wed, 11 Aug 2021 19:35:59 -0500
Subject: [PATCH] changes noticed while working on bindings

---
 src/pixie.nim                  |  12 ++---------
 src/pixie/fileformats/png.nim  |   6 ++----
 src/pixie/images.nim           |  35 +++++++++++++++------------------
 src/pixie/masks.nim            |  10 +++++++++-
 src/pixie/paints.nim           |  32 +++++++++++++++++-------------
 src/pixie/paths.nim            |  16 ++++-----------
 tests/images/masks/shifted.png | Bin 163 -> 0 bytes
 tests/test_images.nim          |   2 +-
 tests/test_masks.nim           |   6 ------
 9 files changed, 52 insertions(+), 67 deletions(-)
 delete mode 100644 tests/images/masks/shifted.png

diff --git a/src/pixie.nim b/src/pixie.nim
index 51900bd..d797132 100644
--- a/src/pixie.nim
+++ b/src/pixie.nim
@@ -69,10 +69,6 @@ proc encodeMask*(mask: Mask, fileFormat: FileFormat): string =
   else:
     raise newException(PixieError, "Unsupported file format")
 
-proc writeFile*(image: Image, filePath: string, fileFormat: FileFormat) =
-  ## Writes an image to a file.
-  writeFile(filePath, image.encodeImage(fileFormat))
-
 proc writeFile*(image: Image, filePath: string) =
   ## Writes an image to a file.
   let fileFormat = case splitFile(filePath).ext.toLowerAscii():
@@ -81,11 +77,7 @@ proc writeFile*(image: Image, filePath: string) =
     of ".jpg", ".jpeg": ffJpg
     else:
       raise newException(PixieError, "Unsupported file extension")
-  image.writeFile(filePath, fileformat)
-
-proc writeFile*(mask: Mask, filePath: string, fileFormat: FileFormat) =
-  ## Writes an mask to a file.
-  writeFile(filePath, mask.encodeMask(fileFormat))
+  writeFile(filePath, image.encodeImage(fileFormat))
 
 proc writeFile*(mask: Mask, filePath: string) =
   ## Writes a mask to a file.
@@ -95,7 +87,7 @@ proc writeFile*(mask: Mask, filePath: string) =
     of ".jpg", ".jpeg": ffJpg
     else:
       raise newException(PixieError, "Unsupported file extension")
-  mask.writeFile(filePath, fileformat)
+  writeFile(filePath, mask.encodeMask(fileFormat))
 
 proc fillRect*(
   mask: Mask,
diff --git a/src/pixie/fileformats/png.nim b/src/pixie/fileformats/png.nim
index 15f488c..c99d10a 100644
--- a/src/pixie/fileformats/png.nim
+++ b/src/pixie/fileformats/png.nim
@@ -421,10 +421,8 @@ proc decodePng*(data: string): Image =
   var pixels = decodeImageData(header, palette, transparency, imageData)
   pixels.toPremultipliedAlpha()
 
-  result = Image()
-  result.width = header.width
-  result.height = header.height
-  result.data = cast[seq[ColorRGBX]](pixels)
+  result = newImage(header.width, header.height)
+  copyMem(result.data[0].addr, pixels[0].addr, pixels.len * 4)
 
 proc encodePng*(width, height, channels: int, data: pointer, len: int): string =
   ## Encodes the image data into the PNG file format.
diff --git a/src/pixie/images.nim b/src/pixie/images.nim
index 7c5fd88..dede0bf 100644
--- a/src/pixie/images.nim
+++ b/src/pixie/images.nim
@@ -71,6 +71,10 @@ proc `[]`*(image: Image, x, y: int): ColorRGBX {.inline.} =
   if image.inside(x, y):
     return image.getRgbaUnsafe(x, y)
 
+proc getColor*(image: Image, x, y: int): Color =
+  ## Gets a color at (x, y) or returns transparent black if outside of bounds.
+  image[x, y].color()
+
 proc setRgbaUnsafe*(image: Image, x, y: int, color: SomeColor) {.inline.} =
   ## Sets a color from (x, y) coordinates.
   ## * No bounds checking *
@@ -83,6 +87,10 @@ proc `[]=`*(image: Image, x, y: int, color: SomeColor) {.inline.} =
   if image.inside(x, y):
     image.setRgbaUnsafe(x, y, color.asRgbx())
 
+proc setColor*(image: Image, x, y: int, color: Color) =
+  ## Sets a color at (x, y) or does nothing if outside of bounds.
+  image[x, y] = color.rgbx()
+
 proc fillUnsafe*(data: var seq[ColorRGBX], color: SomeColor, start, len: int) =
   ## Fills the image data with the parameter color starting at index start and
   ## continuing for len indices.
@@ -807,7 +815,7 @@ proc drawUber(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
         zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
 
 proc draw*(
-  a, b: Image, transform: Vec2 | Mat3 = vec2(), blendMode = bmNormal
+  a, b: Image, transform: Mat3 = mat3(), blendMode = bmNormal
 ) {.inline.} =
   ## Draws one image onto another using matrix with color blending.
   when type(transform) is Vec2:
@@ -816,7 +824,7 @@ proc draw*(
     a.drawUber(b, transform, blendMode)
 
 proc draw*(
-  a, b: Mask, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
+  a, b: Mask, transform: Mat3 = mat3(), blendMode = bmMask
 ) {.inline.} =
   ## Draws a mask onto a mask using a matrix with color blending.
   when type(transform) is Vec2:
@@ -825,7 +833,7 @@ proc draw*(
     a.drawUber(b, transform, blendMode)
 
 proc draw*(
-  image: Image, mask: Mask, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
+  image: Image, mask: Mask, transform: Mat3 = mat3(), blendMode = bmMask
 ) {.inline.} =
   ## Draws a mask onto an image using a matrix with color blending.
   when type(transform) is Vec2:
@@ -834,7 +842,7 @@ proc draw*(
     image.drawUber(mask, transform, blendMode)
 
 proc draw*(
-  mask: Mask, image: Image, transform: Vec2 | Mat3 = vec2(), blendMode = bmMask
+  mask: Mask, image: Image, transform: Mat3 = mat3(), blendMode = bmMask
 ) {.inline.} =
   ## Draws a image onto a mask using a matrix with color blending.
   when type(transform) is Vec2:
@@ -860,25 +868,14 @@ proc resize*(srcImage: Image, width, height: int): Image =
       bmOverwrite
     )
 
-proc shift*(target: Image | Mask, offset: Vec2) =
-  ## Shifts the target by offset.
-  if offset != vec2(0, 0):
-    let copy = target.copy() # Copy to read from
-
-    # Reset target for being drawn to
-    when type(target) is Image:
-      target.fill(rgbx(0, 0, 0, 0))
-    else:
-      target.fill(0)
-
-    target.draw(copy, offset, bmOverwrite) # Draw copy at offset
-
 proc shadow*(
   image: Image, offset: Vec2, spread, blur: float32, color: SomeColor
 ): Image =
   ## Create a shadow of the image with the offset, spread and blur.
-  let mask = image.newMask()
-  mask.shift(offset)
+  let
+    mask = image.newMask()
+    shifted = newMask(mask.width, mask.height)
+  shifted.draw(mask, translate(offset), bmOverwrite)
   mask.spread(spread)
   mask.blur(blur)
   result = newImage(mask.width, mask.height)
diff --git a/src/pixie/masks.nim b/src/pixie/masks.nim
index fdcaa01..b234032 100644
--- a/src/pixie/masks.nim
+++ b/src/pixie/masks.nim
@@ -50,10 +50,14 @@ proc getValueUnsafe*(mask: Mask, x, y: int): uint8 {.inline.} =
   result = mask.data[mask.width * y + x]
 
 proc `[]`*(mask: Mask, x, y: int): uint8 {.inline.} =
-  ## Gets a pixel at (x, y) or returns transparent black if outside of bounds.
+  ## Gets a value at (x, y) or returns transparent black if outside of bounds.
   if mask.inside(x, y):
     return mask.getValueUnsafe(x, y)
 
+proc getValue*(mask: Mask, x, y: int): uint8 {.inline.} =
+  ## Gets a value at (x, y) or returns transparent black if outside of bounds.
+  mask[x, y]
+
 proc setValueUnsafe*(mask: Mask, x, y: int, value: uint8) {.inline.} =
   ## Sets a value from (x, y) coordinates.
   ## * No bounds checking *
@@ -66,6 +70,10 @@ proc `[]=`*(mask: Mask, x, y: int, value: uint8) {.inline.} =
   if mask.inside(x, y):
     mask.setValueUnsafe(x, y, value)
 
+proc setValue*(mask: Mask, x, y: int, value: uint8) {.inline.} =
+  ## Sets a value at (x, y) or does nothing if outside of bounds.
+  mask[x, y] = value
+
 proc minifyBy2*(mask: Mask, power = 1): Mask =
   ## Scales the mask down by an integer scale.
   if power < 0:
diff --git a/src/pixie/paints.nim b/src/pixie/paints.nim
index a6ee40f..5d02a48 100644
--- a/src/pixie/paints.nim
+++ b/src/pixie/paints.nim
@@ -25,8 +25,8 @@ type
 
   ColorStop* = object
     ## Color stop on a gradient curve.
-    color*: ColorRGBX  ## Color of the stop
-    position*: float32 ## Gradient Stop position 0..1.
+    color*: ColorRGBX  ## Color of the stop.
+    position*: float32 ## Gradient stop position 0..1.
 
   SomePaint* = string | Paint | SomeColor
 
@@ -96,12 +96,9 @@ proc gradientPut(
     color = color.applyOpacity(paint.opacity)
   image.setRgbaUnsafe(x, y, color.rgba.rgbx())
 
-proc fillGradientLinear*(image: Image, paint: Paint) =
+proc fillGradientLinear(image: Image, paint: Paint) =
   ## Fills a linear gradient.
 
-  if paint.kind != pkGradientLinear:
-    raise newException(PixieError, "Paint kind must be " & $pkGradientLinear)
-
   if paint.gradientHandlePositions.len != 2:
     raise newException(PixieError, "Linear gradient requires 2 handles")
 
@@ -121,12 +118,9 @@ proc fillGradientLinear*(image: Image, paint: Paint) =
         t = toLineSpace(at, to, xy)
       image.gradientPut(paint, x, y, t, paint.gradientStops)
 
-proc fillGradientRadial*(image: Image, paint: Paint) =
+proc fillGradientRadial(image: Image, paint: Paint) =
   ## Fills a radial gradient.
 
-  if paint.kind != pkGradientRadial:
-    raise newException(PixieError, "Paint kind must be " & $pkGradientRadial)
-
   if paint.gradientHandlePositions.len != 3:
     raise newException(PixieError, "Radial gradient requires 3 handles")
 
@@ -155,12 +149,9 @@ proc fillGradientRadial*(image: Image, paint: Paint) =
         t = (mat * xy).length()
       image.gradientPut(paint, x, y, t, paint.gradientStops)
 
-proc fillGradientAngular*(image: Image, paint: Paint) =
+proc fillGradientAngular(image: Image, paint: Paint) =
   ## Fills an angular gradient.
 
-  if paint.kind != pkGradientAngular:
-    raise newException(PixieError, "Paint kind must be " & $pkGradientAngular)
-
   if paint.gradientHandlePositions.len != 3:
     raise newException(PixieError, "Angular gradient requires 2 handles")
 
@@ -182,3 +173,16 @@ proc fillGradientAngular*(image: Image, paint: Paint) =
         angle = normalize(xy - center).angle()
         t = (angle + gradientAngle + PI / 2).fixAngle() / 2 / PI + 0.5
       image.gradientPut(paint, x, y, t, paint.gradientStops)
+
+proc fillGradient*(image: Image, paint: Paint) =
+  ## Fills with the Paint gradient.
+
+  case paint.kind:
+  of pkGradientLinear:
+    image.fillGradientLinear(paint)
+  of pkGradientRadial:
+    image.fillGradientRadial(paint)
+  of pkGradientAngular:
+    image.fillGradientAngular(paint)
+  else:
+    raise newException(PixieError, "Paint must be a gradient")
diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim
index 53eb836..8c58ea2 100644
--- a/src/pixie/paths.nim
+++ b/src/pixie/paths.nim
@@ -1813,12 +1813,8 @@ proc fillPath*(
       fill.draw(paint.image, paint.imageMat)
     of pkImageTiled:
       fill.drawTiled(paint.image, paint.imageMat)
-    of pkGradientLinear:
-      fill.fillGradientLinear(paint)
-    of pkGradientRadial:
-      fill.fillGradientRadial(paint)
-    of pkGradientAngular:
-      fill.fillGradientAngular(paint)
+    of pkGradientLinear, pkGradientRadial, pkGradientAngular:
+      fill.fillGradient(paint)
 
   paint.opacity = savedOpacity
 
@@ -1909,12 +1905,8 @@ proc strokePath*(
       fill.draw(paint.image, paint.imageMat)
     of pkImageTiled:
       fill.drawTiled(paint.image, paint.imageMat)
-    of pkGradientLinear:
-      fill.fillGradientLinear(paint)
-    of pkGradientRadial:
-      fill.fillGradientRadial(paint)
-    of pkGradientAngular:
-      fill.fillGradientAngular(paint)
+    of pkGradientLinear, pkGradientRadial, pkGradientAngular:
+      fill.fillGradient(paint)
 
   paint.opacity = savedOpacity
 
diff --git a/tests/images/masks/shifted.png b/tests/images/masks/shifted.png
deleted file mode 100644
index 2beb2a4f7e1e57407c0519a1f5e2fcb417ad40cc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 163
zcmeAS@N?(olHy`uVBq!ia0vp^DIm-NBp5<FPjvvPEKe85kP61P7Z&m|C@?TP3W=o`
zZ@3}6;GbB==i-_R9Gc>q;ya7pem!Nn>BZcPmMPuj!J3n$3=a=Q>!{ZJ^aR=N>FVdQ
I&MBb@03N+T@c;k-

diff --git a/tests/test_images.nim b/tests/test_images.nim
index a0d0f3c..13b3da0 100644
--- a/tests/test_images.nim
+++ b/tests/test_images.nim
@@ -43,7 +43,7 @@ block:
   a.fill(rgba(255, 0, 0, 255))
   b.fill(rgba(0, 255, 0, 255))
 
-  a.draw(b, vec2(0, 0))
+  a.draw(b, translate(vec2(0, 0)))
 
   a.writeFile("tests/images/flipped1.png")
   a.flipVertical()
diff --git a/tests/test_masks.nim b/tests/test_masks.nim
index d352902..ef72e94 100644
--- a/tests/test_masks.nim
+++ b/tests/test_masks.nim
@@ -75,12 +75,6 @@ block:
   a.draw(b)
   writeFile("tests/images/masks/imageMaskedMask.png", a.encodePng())
 
-block:
-  let a = newMask(100, 100)
-  a.fill(255)
-  a.shift(vec2(10, 10))
-  writeFile("tests/images/masks/shifted.png", a.encodePng())
-
 block:
   let path = newPath()
   path.rect(40, 40, 20, 20)