Skip to content

Commit

Permalink
Merge pull request #3 from trafi/feature/shadow
Browse files Browse the repository at this point in the history
Shadow
  • Loading branch information
Domas Nutautas authored Jul 24, 2020
2 parents a4278b6 + 4a29685 commit 5b81ee2
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Sources/ImageMod/ImageMod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ public struct ImageMod {
var canvasSize: CGSize
var drawRect: CGRect
var tint: UIColor?
var shadow: (offset: CGPoint, blur: CGFloat, color: UIColor)?

init(_ size: CGSize) {
canvasSize = size
drawRect = CGRect(origin: .zero, size: size)
tint = nil
shadow = nil
}
}

Expand Down
12 changes: 12 additions & 0 deletions Sources/ImageMod/ImageModable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ public extension ImageModable {
}
}

// MARK: Shadowed

func shadowed(offset: CGPoint = .zero, blur: CGFloat, color: UIColor = UIColor.black.withAlphaComponent(1/3)) -> ImageModable {
padded(top: max(0, blur - offset.y),
left: max(0, blur - offset.x),
bottom: max(0, blur + offset.y),
right: max(0, blur + offset.x))
.with {
$0.shadow = (offset, blur, color)
}
}

// MARK: Padded

func padded(top: CGFloat = 0, left: CGFloat = 0, bottom: CGFloat = 0, right: CGFloat = 0) -> ImageModable {
Expand Down
17 changes: 16 additions & 1 deletion Sources/ImageMod/UIImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ extension UIImage: ImageModable {
ImageMod(info: .init(size),
draw: { info in
self.withTintColor(info.tint, optimizedFor: info.drawRect.size)
.draw(in: info.drawRect)
.draw(in: info.drawRect, with: info.shadow)
})
}

Expand All @@ -23,4 +23,19 @@ extension UIImage: ImageModable {
}
}
}

private func draw(in rect: CGRect, with shadow: (offset: CGPoint, blur: CGFloat, color: UIColor)?) {

let ctx = UIGraphicsGetCurrentContext()!
ctx.saveGState()
defer { ctx.restoreGState() }

if let shadow = shadow {
ctx.setShadow(offset: CGSize(width: shadow.offset.x, height: shadow.offset.y),
blur: shadow.blur,
color: shadow.color.cgColor)
}

draw(in: rect)
}
}
55 changes: 55 additions & 0 deletions Tests/ImageModTests/ShadowTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import XCTest
@testable import ImageMod

final class ShadowTests: ModTests {

func test_itUsesShadowAndAddsPaddingForIt() {

_ = mod
.shadowed(offset: CGPoint(x: 2, y: 4), blur: 10, color: .red)
.image

XCTAssertEqual(mod.info.shadow?.offset, CGPoint(x: 2, y: 4))
XCTAssertEqual(mod.info.shadow?.blur, 10)
XCTAssertEqual(mod.info.shadow?.color, .red)

XCTAssertEqual(mod.info.canvasSize, CGSize(width: 120, height: 120))
XCTAssertEqual(mod.info.drawRect, CGRect(x: 8, y: 6, width: 100, height: 100))
}

func test_itHandlesOffsetLargerThanBlur() {

_ = mod
.shadowed(offset: CGPoint(x: 20, y: 40), blur: 10)
.image

XCTAssertEqual(mod.info.shadow?.offset, CGPoint(x: 20, y: 40))
XCTAssertEqual(mod.info.shadow?.blur, 10)

XCTAssertEqual(mod.info.canvasSize, CGSize(width: 130, height: 150))
XCTAssertEqual(mod.info.drawRect, CGRect(x: 0, y: 0, width: 100, height: 100))

}

func test_itUsesDefaultOffsetAndColor() {

_ = mod
.shadowed(blur: 10)
.image

XCTAssertEqual(mod.info.shadow?.offset, .zero)
XCTAssertEqual(mod.info.shadow?.blur, 10)
XCTAssertEqual(mod.info.shadow?.color, UIColor.black.withAlphaComponent(1/3))
}

func testChaining_itUsesLastShadow() {

_ = mod
.shadowed(blur: 10, color: .red)
.shadowed(blur: 20, color: .blue)
.image

XCTAssertEqual(mod.info.shadow?.blur, 20)
XCTAssertEqual(mod.info.shadow?.color, .blue)
}
}
14 changes: 13 additions & 1 deletion Tests/ImageModTests/UIImageTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,23 @@ final class UIImageTests: XCTestCase {
.scaled(to: CGSize(width: 200, height: 100))
.padded(by: 10)
.tinted(.red)
.zStack(blackSquare
.shadowed(offset: CGPoint(x: 2, y: 4), blur: 8, color: .green)
.padded(top: 8, left: 4)
)
.hStack(blackSquare, spacing: 10, alignment: .top)
.image

let image = UIGraphicsImageRenderer(size: CGSize(width: 220, height: 120)).image { context in
let image = UIGraphicsImageRenderer(size: CGSize(width: 240, height: 120)).image { context in
UIColor.red.setFill()
context.fill(CGRect(x: 10, y: 10, width: 200, height: 100))

UIColor.black.setFill()
context.cgContext.setShadow(offset: CGSize(width: 2, height: 4), blur: 8, color: UIColor.green.cgColor)
context.fill(CGRect(x: 105, y: 55, width: 10, height: 10))

context.cgContext.setShadow(offset: .zero, blur: 0, color: nil)
context.fill(CGRect(x: 230, y: 0, width: 10, height: 10))
}

XCTAssertEqual(sut.pngData(), image.pngData())
Expand Down

0 comments on commit 5b81ee2

Please sign in to comment.