Skip to content

Commit 771ddc2

Browse files
committed
Implement subscripts by ranges with extrapolation
1 parent ffdecc7 commit 771ddc2

7 files changed

Lines changed: 206 additions & 25 deletions

File tree

EasyImagy.xcodeproj/project.pbxproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@
142142
D6B4EE211FE2699700B6B7B0 /* AnyImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE201FE2699700B6B7B0 /* AnyImageTests.swift */; };
143143
D6B4EE221FE2699700B6B7B0 /* AnyImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE201FE2699700B6B7B0 /* AnyImageTests.swift */; };
144144
D6B4EE231FE2699700B6B7B0 /* AnyImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE201FE2699700B6B7B0 /* AnyImageTests.swift */; };
145+
D6B4EE251FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */; };
146+
D6B4EE261FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */; };
147+
D6B4EE271FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */; };
148+
D6B4EE281FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */; };
145149
D6C1C01E1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1C01D1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift */; };
146150
D6C1C01F1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1C01D1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift */; };
147151
D6C1C0201FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1C01D1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift */; };
@@ -152,10 +156,6 @@
152156
D6FAC86B1FD1938400509BCB /* ImageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC8691FD1938400509BCB /* ImageProtocol.swift */; };
153157
D6FAC86C1FD1938400509BCB /* ImageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC8691FD1938400509BCB /* ImageProtocol.swift */; };
154158
D6FAC86D1FD1938400509BCB /* ImageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC8691FD1938400509BCB /* ImageProtocol.swift */; };
155-
D6FAC86F1FD8423F00509BCB /* ImageSliceInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */; };
156-
D6FAC8701FD8423F00509BCB /* ImageSliceInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */; };
157-
D6FAC8711FD8423F00509BCB /* ImageSliceInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */; };
158-
D6FAC8721FD8423F00509BCB /* ImageSliceInternal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */; };
159159
/* End PBXBuildFile section */
160160

161161
/* Begin PBXContainerItemProxy section */
@@ -230,10 +230,10 @@
230230
D6B4EE161FE2038000B6B7B0 /* ImageFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFormat.swift; sourceTree = "<group>"; };
231231
D6B4EE1B1FE25C0600B6B7B0 /* AnyImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyImage.swift; sourceTree = "<group>"; };
232232
D6B4EE201FE2699700B6B7B0 /* AnyImageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyImageTests.swift; sourceTree = "<group>"; };
233+
D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrapolatedImage.swift; sourceTree = "<group>"; };
233234
D6C1C01D1FDFCB2500CAA6C4 /* HigherOrderFunctionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HigherOrderFunctionsTests.swift; sourceTree = "<group>"; };
234235
D6D33DBA1FD97A8B00256FD0 /* ImageProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProtocolTests.swift; sourceTree = "<group>"; };
235236
D6FAC8691FD1938400509BCB /* ImageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProtocol.swift; sourceTree = "<group>"; };
236-
D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSliceInternal.swift; sourceTree = "<group>"; };
237237
/* End PBXFileReference section */
238238

239239
/* Begin PBXFrameworksBuildPhase section */
@@ -329,6 +329,7 @@
329329
D6B4EE1B1FE25C0600B6B7B0 /* AnyImage.swift */,
330330
D63109111FCFD7DE009974D0 /* Convolution.swift */,
331331
D6134A2A1F852A49005592A2 /* EasyImagy.h */,
332+
D6B4EE241FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift */,
332333
D62C6EDE1FCE6BD800E7DF02 /* Extrapolation.swift */,
333334
D62C6EC61FCC18E600E7DF02 /* HigherOrderFunctions.swift */,
334335
D6134A2B1F852A49005592A2 /* Image.swift */,
@@ -340,7 +341,6 @@
340341
D6FAC8691FD1938400509BCB /* ImageProtocol.swift */,
341342
D6134A2F1F852A49005592A2 /* ImageProtocolTyped.swift */,
342343
D6134A2E1F852A49005592A2 /* ImageSlice.swift */,
343-
D6FAC86E1FD8423F00509BCB /* ImageSliceInternal.swift */,
344344
D6134A301F852A49005592A2 /* ImageUIKit.swift */,
345345
D6134A311F852A49005592A2 /* Info.plist */,
346346
D62C6ED41FCE55EB00E7DF02 /* Interpolation.swift */,
@@ -675,6 +675,7 @@
675675
files = (
676676
D6134A5A1F852A85005592A2 /* Util.swift in Sources */,
677677
D6134A511F852A85005592A2 /* ImageAppKit.swift in Sources */,
678+
D6B4EE251FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */,
678679
D66840591F9F426200D1DE7F /* Summable.swift in Sources */,
679680
D62C6EDF1FCE6BD800E7DF02 /* Extrapolation.swift in Sources */,
680681
D6FAC86A1FD1938400509BCB /* ImageProtocol.swift in Sources */,
@@ -694,7 +695,6 @@
694695
D60D48A51FA0E3360047F2D3 /* ImageInternal.swift in Sources */,
695696
D6B4EE171FE2038000B6B7B0 /* ImageFormat.swift in Sources */,
696697
D631091F1FCFFB4C009974D0 /* ImageOperators.swift in Sources */,
697-
D6FAC86F1FD8423F00509BCB /* ImageSliceInternal.swift in Sources */,
698698
);
699699
runOnlyForDeploymentPostprocessing = 0;
700700
};
@@ -729,6 +729,7 @@
729729
files = (
730730
D62C6EBB1FC9DAD900E7DF02 /* RGBATyped.swift in Sources */,
731731
D6134A851F85CF5E005592A2 /* Util.swift in Sources */,
732+
D6B4EE261FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */,
732733
D6134A7C1F85CF5E005592A2 /* ImageAppKit.swift in Sources */,
733734
D62C6EE01FCE6BD800E7DF02 /* Extrapolation.swift in Sources */,
734735
D6FAC86B1FD1938400509BCB /* ImageProtocol.swift in Sources */,
@@ -748,7 +749,6 @@
748749
D62C6EBE1FC9DB4200E7DF02 /* ImageInternal.swift in Sources */,
749750
D6B4EE181FE2038000B6B7B0 /* ImageFormat.swift in Sources */,
750751
D63109201FCFFB4C009974D0 /* ImageOperators.swift in Sources */,
751-
D6FAC8701FD8423F00509BCB /* ImageSliceInternal.swift in Sources */,
752752
);
753753
runOnlyForDeploymentPostprocessing = 0;
754754
};
@@ -783,6 +783,7 @@
783783
files = (
784784
D62C6EBC1FC9DADA00E7DF02 /* RGBATyped.swift in Sources */,
785785
D6134AC41F85D2AF005592A2 /* Util.swift in Sources */,
786+
D6B4EE271FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */,
786787
D6134ABB1F85D2AF005592A2 /* ImageAppKit.swift in Sources */,
787788
D62C6EE11FCE6BD800E7DF02 /* Extrapolation.swift in Sources */,
788789
D6FAC86C1FD1938400509BCB /* ImageProtocol.swift in Sources */,
@@ -802,7 +803,6 @@
802803
D62C6EBF1FC9DB4300E7DF02 /* ImageInternal.swift in Sources */,
803804
D6B4EE191FE2038000B6B7B0 /* ImageFormat.swift in Sources */,
804805
D63109211FCFFB4C009974D0 /* ImageOperators.swift in Sources */,
805-
D6FAC8711FD8423F00509BCB /* ImageSliceInternal.swift in Sources */,
806806
);
807807
runOnlyForDeploymentPostprocessing = 0;
808808
};
@@ -837,6 +837,7 @@
837837
files = (
838838
D62C6EBD1FC9DADB00E7DF02 /* RGBATyped.swift in Sources */,
839839
D6134AE51F85DA5C005592A2 /* Util.swift in Sources */,
840+
D6B4EE281FE2BF1F00B6B7B0 /* ExtrapolatedImage.swift in Sources */,
840841
D6134ADC1F85DA5C005592A2 /* ImageAppKit.swift in Sources */,
841842
D62C6EE21FCE6BD800E7DF02 /* Extrapolation.swift in Sources */,
842843
D6FAC86D1FD1938400509BCB /* ImageProtocol.swift in Sources */,
@@ -856,7 +857,6 @@
856857
D62C6EC01FC9DB4400E7DF02 /* ImageInternal.swift in Sources */,
857858
D6B4EE1A1FE2038000B6B7B0 /* ImageFormat.swift in Sources */,
858859
D63109221FCFFB4C009974D0 /* ImageOperators.swift in Sources */,
859-
D6FAC8721FD8423F00509BCB /* ImageSliceInternal.swift in Sources */,
860860
);
861861
runOnlyForDeploymentPostprocessing = 0;
862862
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
private func offset(_ range: CountableRange<Int>, _ offset: Int) -> CountableRange<Int> {
2+
return (range.lowerBound + offset) ..< (range.upperBound + offset)
3+
}
4+
5+
internal struct ExtrapolatedImage<Pixel> : ImageProtocol {
6+
private var image: AnyImage<Pixel>
7+
public let xRange: CountableRange<Int>
8+
public let yRange: CountableRange<Int>
9+
private let extrapolationMethod: ExtrapolationMethod<Pixel>
10+
private var offsetX: Int
11+
private var offsetY: Int
12+
13+
internal init(image: AnyImage<Pixel>, xRange: CountableRange<Int>, yRange: CountableRange<Int>, extrapolationMethod: ExtrapolationMethod<Pixel>, offsetX: Int = 0, offsetY: Int = 0) {
14+
self.image = image
15+
self.xRange = xRange
16+
self.yRange = yRange
17+
self.extrapolationMethod = extrapolationMethod
18+
self.offsetX = offsetX
19+
self.offsetY = offsetY
20+
}
21+
22+
public subscript(x: Int, y: Int) -> Pixel {
23+
get {
24+
return image[x + offsetX, y + offsetY, extrapolatedBy: extrapolationMethod]
25+
}
26+
27+
set {
28+
assert(xRange.contains(x), "`x` is out of bounds: \(x)")
29+
assert(yRange.contains(y), "`y` is out of bounds: \(y)")
30+
if !image.xRange.contains(x) || !image.yRange.contains(y) {
31+
var pixels = [Pixel]()
32+
for y in yRange {
33+
for x in xRange {
34+
pixels.append(self[x, y])
35+
}
36+
}
37+
image = AnyImage<Pixel>(Image<Pixel>(width: xRange.count, height: yRange.count, pixels: pixels))
38+
offsetX = -xRange.lowerBound
39+
offsetY = -yRange.lowerBound
40+
}
41+
image[x + offsetX, y + offsetY] = newValue
42+
}
43+
}
44+
45+
public subscript(xRange: CountableRange<Int>, yRange: CountableRange<Int>) -> ImageSlice<Pixel> {
46+
return ImageSlice<Pixel>(image: AnyImage<Pixel>(self), xRange: xRange, yRange: yRange)
47+
}
48+
49+
public func makeIterator() -> AnyIterator<Pixel> {
50+
fatalError("This method is never called.")
51+
}
52+
}

Sources/EasyImagy/Extrapolation.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,34 @@ extension ImageProtocol {
7171
return self[x3, y3]
7272
}
7373
}
74+
75+
extension ImageProtocol {
76+
public subscript(xRange: CountableRange<Int>, yRange: CountableRange<Int>, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> ImageSlice<Pixel> {
77+
return ImageSlice<Pixel>(
78+
image: ExtrapolatedImage<Pixel>(
79+
image: AnyImage<Pixel>(self),
80+
xRange: xRange,
81+
yRange: yRange,
82+
extrapolationMethod: extrapolationMethod
83+
),
84+
xRange: xRange,
85+
yRange: yRange
86+
)
87+
}
88+
89+
public subscript<R1: RangeExpression, R2: RangeExpression>(xRange: R1, yRange: R2, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> ImageSlice<Pixel> where R1.Bound == Int, R2.Bound == Int {
90+
return self[countableRange(from: xRange, relativeTo: self.xRange), countableRange(from: yRange, relativeTo: self.yRange), extrapolatedBy: extrapolationMethod]
91+
}
92+
93+
public subscript<R1: RangeExpression>(xRange: R1, yRange: UnboundedRange, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> ImageSlice<Pixel> where R1.Bound == Int {
94+
return self[countableRange(from: xRange, relativeTo: self.xRange), self.yRange, extrapolatedBy: extrapolationMethod]
95+
}
96+
97+
public subscript<R2: RangeExpression>(xRange: UnboundedRange, yRange: R2, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> ImageSlice<Pixel> where R2.Bound == Int {
98+
return self[self.xRange, countableRange(from: yRange, relativeTo: self.yRange), extrapolatedBy: extrapolationMethod]
99+
}
100+
101+
public subscript(xRange: UnboundedRange, yRange: UnboundedRange, extrapolatedBy extrapolationMethod: ExtrapolationMethod<Pixel>) -> ImageSlice<Pixel> {
102+
return self[self.xRange, self.yRange, extrapolatedBy: extrapolationMethod]
103+
}
104+
}

Sources/EasyImagy/ImageSlice.swift

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
public struct ImageSlice<Pixel> : ImageProtocol {
2-
internal var image: AnyImage<Pixel>
2+
private var image: AnyImage<Pixel>
33
public let xRange: CountableRange<Int>
44
public let yRange: CountableRange<Int>
5+
private let extrapolationMethod: ExtrapolationMethod<Pixel>?
56

7+
internal init<I : ImageProtocol>(image: I, xRange: CountableRange<Int>, yRange: CountableRange<Int>, extrapolationMethod: ExtrapolationMethod<Pixel>? = nil) where I.Pixel == Pixel {
8+
precondition(image.xRange.isSuperset(of: xRange), "`xRange` is out of bounds: \(xRange)")
9+
precondition(image.yRange.isSuperset(of: yRange), "`yRange` is out of bounds: \(yRange)")
10+
self.image = AnyImage<Pixel>(image)
11+
self.xRange = xRange
12+
self.yRange = yRange
13+
self.extrapolationMethod = extrapolationMethod
14+
}
15+
616
public init(width: Int, height: Int, pixels: [Pixel]) {
717
self.init(image: Image<Pixel>(width: width, height: height, pixels: pixels), xRange: 0..<width, yRange: 0..<height)
818
}
@@ -11,20 +21,33 @@ public struct ImageSlice<Pixel> : ImageProtocol {
1121
get {
1222
precondition(xRange.contains(x), "`x` is out of bounds: \(x)")
1323
precondition(yRange.contains(y), "`y` is out of bounds: \(y)")
14-
return image[x, y]
24+
if let extrapolationMethod = extrapolationMethod {
25+
return image[x, y, extrapolatedBy: extrapolationMethod]
26+
} else {
27+
return image[x, y]
28+
}
1529
}
1630

1731
set {
1832
precondition(xRange.contains(x), "`x` is out of bounds: \(x)")
1933
precondition(yRange.contains(y), "`y` is out of bounds: \(y)")
20-
image[x, y] = newValue
34+
if let extrapolationMethod = extrapolationMethod {
35+
// TODO
36+
fatalError("Unimplemented: \(extrapolationMethod)")
37+
} else {
38+
image[x, y] = newValue
39+
}
2140
}
2241
}
2342

2443
public subscript(xRange: CountableRange<Int>, yRange: CountableRange<Int>) -> ImageSlice<Pixel> {
2544
precondition(self.xRange.isSuperset(of: xRange), "`xRange` is out of bounds: \(xRange)")
2645
precondition(self.xRange.isSuperset(of: yRange), "`yRange` is out of bounds: \(yRange)")
27-
return image[xRange, yRange]
46+
if let extrapolationMethod = extrapolationMethod {
47+
return image[xRange, yRange, extrapolatedBy: extrapolationMethod]
48+
} else {
49+
return image[xRange, yRange]
50+
}
2851
}
2952
}
3053

Sources/EasyImagy/ImageSliceInternal.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.

Sources/EasyImagy/Util.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,21 @@ extension CountableRange {
1313
}
1414

1515
internal func countableRange<R: RangeExpression>(from range: R, relativeTo collection: CountableRange<Int>) -> CountableRange<Int> where R.Bound == Int {
16-
return CountableRange(range.relative(to: collection))
16+
let all = Int.min ..< Int.max
17+
let boundedRange: Range<Int> = range.relative(to: all)
18+
let lowerBound: Int
19+
let upperBound: Int
20+
if boundedRange.lowerBound == .min {
21+
lowerBound = Swift.max(boundedRange.lowerBound, collection.lowerBound)
22+
} else {
23+
lowerBound = boundedRange.lowerBound
24+
}
25+
if boundedRange.upperBound == .max {
26+
upperBound = Swift.min(collection.upperBound, boundedRange.upperBound)
27+
} else {
28+
upperBound = boundedRange.upperBound
29+
}
30+
return lowerBound..<upperBound
1731
}
1832

1933
internal func countableRange(from range: CountableRange<Int>, relativeTo collection: CountableRange<Int>) -> CountableRange<Int> {

Tests/EasyImagyTests/ExtrapolationTests.swift

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import XCTest
22
import EasyImagy
33

44
class ExtrapolationTests: XCTestCase {
5-
func testSubscriptExtrapolation() {
5+
func testSubscriptWithExtrapolation() {
66
do {
77
let image = Image<UInt8>(width: 3, height: 3, pixels: [
88
1, 2, 3,
@@ -462,4 +462,74 @@ class ExtrapolationTests: XCTestCase {
462462
}
463463
}
464464
}
465+
466+
func testSubscriptRangeWithExtrapolation() {
467+
do {
468+
let image = Image<UInt8>(width: 3, height: 2, pixels: [
469+
1, 2, 3,
470+
4, 5, 6,
471+
])
472+
var slice = image[-4...6, -3...4, extrapolatedBy: .mirroring]
473+
474+
XCTAssertEqual(slice, ImageSlice<UInt8>(width: 11, height: 8, pixels: [
475+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
476+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
477+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
478+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
479+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
480+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
481+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
482+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
483+
]))
484+
XCTAssertEqual(slice[-2, -1], 2)
485+
486+
slice[-2, -1] = 9
487+
488+
XCTAssertEqual(slice, ImageSlice<UInt8>(width: 11, height: 8, pixels: [
489+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
490+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
491+
3, 3, 9, 1, 1, 2, 3, 3, 2, 1, 1,
492+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
493+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
494+
6, 6, 5, 4, 4, 5, 6, 6, 5, 4, 4,
495+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
496+
3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1,
497+
]))
498+
XCTAssertEqual(slice[-2, -1], 9)
499+
}
500+
501+
do {
502+
let image = Image<UInt8>(width: 3, height: 2, pixels: [
503+
1, 2, 3,
504+
4, 5, 6,
505+
])
506+
let a = image[-1 ... 0, -1...0, extrapolatedBy: .repeating]
507+
508+
XCTAssertEqual(a, ImageSlice<UInt8>(width: 2, height: 2, pixels: [
509+
6, 4,
510+
3, 1,
511+
]))
512+
513+
var b = a[-4 ... -1, -3 ... -1, extrapolatedBy: .mirroring]
514+
let c = b
515+
516+
XCTAssertEqual(b, ImageSlice<UInt8>(width: 4, height: 3, pixels: [
517+
1, 1, 3, 3,
518+
4, 4, 6, 6,
519+
4, 4, 6, 6,
520+
]))
521+
XCTAssertEqual(b[-3, -3], 1)
522+
XCTAssertEqual(c[-3, -3], 1)
523+
524+
b[-3, -3] = 9
525+
526+
XCTAssertEqual(b, ImageSlice<UInt8>(width: 4, height: 3, pixels: [
527+
1, 9, 3, 3,
528+
4, 4, 6, 6,
529+
4, 4, 6, 6,
530+
]))
531+
XCTAssertEqual(b[-3, -3], 9)
532+
XCTAssertEqual(c[-3, -3], 1)
533+
}
534+
}
465535
}

0 commit comments

Comments
 (0)