Skip to content

Commit 6ef7c5d

Browse files
dflemsstephencelismbrandonw
authored andcommitted
Compare image contexts in same colorspace (pointfreeco#446)
Co-authored-by: Stephen Celis <[email protected]> Co-authored-by: Brandon Williams <[email protected]>
1 parent 7065dd1 commit 6ef7c5d

File tree

1 file changed

+14
-13
lines changed

1 file changed

+14
-13
lines changed

Sources/SnapshotTesting/Snapshotting/UIImage.swift

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ extension Snapshotting where Value == UIImage, Format == UIImage {
8080
}
8181
}
8282

83+
// remap snapshot & reference to same colorspace
84+
let imageContextColorSpace = CGColorSpace(name: CGColorSpace.sRGB)
85+
let imageContextBitsPerComponent = 8
86+
let imageContextBytesPerPixel = 4
87+
8388
private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
8489
guard let oldCgImage = old.cgImage else { return false }
8590
guard let newCgImage = new.cgImage else { return false }
@@ -89,23 +94,18 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
8994
guard oldCgImage.height != 0 else { return false }
9095
guard newCgImage.height != 0 else { return false }
9196
guard oldCgImage.height == newCgImage.height else { return false }
92-
// Values between images may differ due to padding to multiple of 64 bytes per row,
93-
// because of that a freshly taken view snapshot may differ from one stored as PNG.
94-
// At this point we're sure that size of both images is the same, so we can go with minimal `bytesPerRow` value
95-
// and use it to create contexts.
96-
let minBytesPerRow = min(oldCgImage.bytesPerRow, newCgImage.bytesPerRow)
97-
let byteCount = minBytesPerRow * oldCgImage.height
9897

98+
let byteCount = imageContextBytesPerPixel * oldCgImage.width * oldCgImage.height
9999
var oldBytes = [UInt8](repeating: 0, count: byteCount)
100-
guard let oldContext = context(for: oldCgImage, bytesPerRow: minBytesPerRow, data: &oldBytes) else { return false }
100+
guard let oldContext = context(for: oldCgImage, data: &oldBytes) else { return false }
101101
guard let oldData = oldContext.data else { return false }
102-
if let newContext = context(for: newCgImage, bytesPerRow: minBytesPerRow), let newData = newContext.data {
102+
if let newContext = context(for: newCgImage), let newData = newContext.data {
103103
if memcmp(oldData, newData, byteCount) == 0 { return true }
104104
}
105105
let newer = UIImage(data: new.pngData()!)!
106106
guard let newerCgImage = newer.cgImage else { return false }
107107
var newerBytes = [UInt8](repeating: 0, count: byteCount)
108-
guard let newerContext = context(for: newerCgImage, bytesPerRow: minBytesPerRow, data: &newerBytes) else { return false }
108+
guard let newerContext = context(for: newerCgImage, data: &newerBytes) else { return false }
109109
guard let newerData = newerContext.data else { return false }
110110
if memcmp(oldData, newerData, byteCount) == 0 { return true }
111111
if precision >= 1 { return false }
@@ -118,16 +118,17 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float) -> Bool {
118118
return true
119119
}
120120

121-
private func context(for cgImage: CGImage, bytesPerRow: Int, data: UnsafeMutableRawPointer? = nil) -> CGContext? {
121+
private func context(for cgImage: CGImage, data: UnsafeMutableRawPointer? = nil) -> CGContext? {
122+
let bytesPerRow = cgImage.width * imageContextBytesPerPixel
122123
guard
123-
let space = cgImage.colorSpace,
124+
let colorSpace = imageContextColorSpace,
124125
let context = CGContext(
125126
data: data,
126127
width: cgImage.width,
127128
height: cgImage.height,
128-
bitsPerComponent: cgImage.bitsPerComponent,
129+
bitsPerComponent: imageContextBitsPerComponent,
129130
bytesPerRow: bytesPerRow,
130-
space: space,
131+
space: colorSpace,
131132
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
132133
)
133134
else { return nil }

0 commit comments

Comments
 (0)