Skip to content

Commit

Permalink
Apply fix from pointfreeco#446
Browse files Browse the repository at this point in the history
Credit to @dflems
  • Loading branch information
zenangst committed Apr 21, 2021
1 parent 32ebb83 commit 7c8b8ff
Showing 1 changed file with 16 additions and 15 deletions.
31 changes: 16 additions & 15 deletions Sources/SnapshotTesting/Snapshotting/UIImage.swift
Expand Up @@ -32,8 +32,8 @@ extension Diffing where Value == UIImage {
)
}
}


/// Used when the image size has no width or no height to generated the default empty image
private static func emptyImage() -> UIImage {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 400, height: 80))
Expand Down Expand Up @@ -62,6 +62,11 @@ extension Snapshotting where Value == UIImage, Format == UIImage {
}
}

// remap snapshot & reference to same colorspace
let imageContextColorSpace = CGColorSpace(name: CGColorSpace.sRGB)
let imageContextBitsPerComponent = 8
let imageContextBytesPerPixel = 4

private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
guard let oldCgImage = old.cgImage else { return false }
guard let newCgImage = new.cgImage else { return false }
Expand All @@ -71,23 +76,18 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
guard oldCgImage.height != 0 else { return false }
guard newCgImage.height != 0 else { return false }
guard oldCgImage.height == newCgImage.height else { return false }
// Values between images may differ due to padding to multiple of 64 bytes per row,
// because of that a freshly taken view snapshot may differ from one stored as PNG.
// At this point we're sure that size of both images is the same, so we can go with minimal `bytesPerRow` value
// and use it to create contexts.
let minBytesPerRow = min(oldCgImage.bytesPerRow, newCgImage.bytesPerRow)
let byteCount = minBytesPerRow * oldCgImage.height

let byteCount = imageContextBytesPerPixel * oldCgImage.width * oldCgImage.height
var oldBytes = [UInt8](repeating: 0, count: byteCount)
guard let oldContext = context(for: oldCgImage, bytesPerRow: minBytesPerRow, data: &oldBytes) else { return false }
guard let oldContext = context(for: oldCgImage, data: &oldBytes) else { return false }
guard let oldData = oldContext.data else { return false }
if let newContext = context(for: newCgImage, bytesPerRow: minBytesPerRow), let newData = newContext.data {
if let newContext = context(for: newCgImage), let newData = newContext.data {
if memcmp(oldData, newData, byteCount) == 0 { return true }
}
let newer = UIImage(data: new.pngData()!)!
guard let newerCgImage = newer.cgImage else { return false }
var newerBytes = [UInt8](repeating: 0, count: byteCount)
guard let newerContext = context(for: newerCgImage, bytesPerRow: minBytesPerRow, data: &newerBytes) else { return false }
guard let newerContext = context(for: newerCgImage, data: &newerBytes) else { return false }
guard let newerData = newerContext.data else { return false }
if memcmp(oldData, newerData, byteCount) == 0 { return true }
if precision >= 1 { return false }
Expand All @@ -100,16 +100,17 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
return true
}

private func context(for cgImage: CGImage, bytesPerRow: Int, data: UnsafeMutableRawPointer? = nil) -> CGContext? {
private func context(for cgImage: CGImage, data: UnsafeMutableRawPointer? = nil) -> CGContext? {
let bytesPerRow = cgImage.width * imageContextBytesPerPixel
guard
let space = cgImage.colorSpace,
let colorSpace = imageContextColorSpace,
let context = CGContext(
data: data,
width: cgImage.width,
height: cgImage.height,
bitsPerComponent: cgImage.bitsPerComponent,
bitsPerComponent: imageContextBitsPerComponent,
bytesPerRow: bytesPerRow,
space: space,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
)
else { return nil }
Expand Down

0 comments on commit 7c8b8ff

Please sign in to comment.