Skip to content

Commit 327a64a

Browse files
committed
Added assessment status.
1 parent cca5fa2 commit 327a64a

File tree

12 files changed

+119
-32
lines changed

12 files changed

+119
-32
lines changed

ArtOfAscii.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
B99F62C10DF5FE5C2DFEB8ED /* HistogramToolBarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F60791EAC8292C8B51B84 /* HistogramToolBarButtonView.swift */; };
6060
B99F639B7680E4364A3F18F0 /* ToolBarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F68271AC771FBF80CA432 /* ToolBarButtonView.swift */; };
6161
B99F6400E1E57AF2E5AB4976 /* ImagePickerCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6C77380C3A46808255C9 /* ImagePickerCollectionViewCell.swift */; };
62+
B99F6442E80A97F3F2886E33 /* AssessmentHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F613810CFF6CDF4819C61 /* AssessmentHelper.swift */; };
6263
B99F649C83DCDA708FA85400 /* ScaleModeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F61BE43A6CBB41B9BFCD8 /* ScaleModeButton.swift */; };
6364
B99F65A6F8520A258E17F0B0 /* AsciiEffectsProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6E60E7631B2E9BA0B4CB /* AsciiEffectsProcessor.swift */; };
6465
B99F65EBA0B2B605EAF4B0D9 /* UIColor+StateColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99F6CB6047723F571693553 /* UIColor+StateColors.swift */; };
@@ -222,6 +223,7 @@
222223
B99F60791EAC8292C8B51B84 /* HistogramToolBarButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistogramToolBarButtonView.swift; sourceTree = "<group>"; };
223224
B99F60BBADE4C030CE20A8A7 /* PlainEffectProcessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlainEffectProcessor.swift; sourceTree = "<group>"; };
224225
B99F61225990694C8BFFFE09 /* ImagePickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerViewController.swift; sourceTree = "<group>"; };
226+
B99F613810CFF6CDF4819C61 /* AssessmentHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssessmentHelper.swift; sourceTree = "<group>"; };
225227
B99F6180FC417C8E454D3884 /* MagnivierContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagnivierContainerView.swift; sourceTree = "<group>"; };
226228
B99F61BE43A6CBB41B9BFCD8 /* ScaleModeButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScaleModeButton.swift; sourceTree = "<group>"; };
227229
B99F62ACBBE87D8546FAB866 /* EventListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventListener.swift; sourceTree = "<group>"; };
@@ -503,6 +505,7 @@
503505
isa = PBXGroup;
504506
children = (
505507
B99F62ACBBE87D8546FAB866 /* EventListener.swift */,
508+
B99F613810CFF6CDF4819C61 /* AssessmentHelper.swift */,
506509
);
507510
path = Sources;
508511
sourceTree = "<group>";
@@ -894,6 +897,7 @@
894897
B99F698222E0FA36B49D9E8C /* AsciiArtRenderer+Internal.swift in Sources */,
895898
B99F61A44EA28889402486FC /* ImagePickerDataSource.swift in Sources */,
896899
B99F66914F6A7B926EF51DF9 /* PhotoAlbumSavable.swift in Sources */,
900+
B99F6442E80A97F3F2886E33 /* AssessmentHelper.swift in Sources */,
897901
);
898902
runOnlyForDeploymentPostprocessing = 0;
899903
};

ArtOfAscii/Chapters/01-ArtOfAscii.playgroundchapter/Pages/01-Introduction.playgroundpage/main.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import PlaygroundSupport
99

1010
PlaygroundPage.current.needsIndefiniteExecution = true
1111

12+
let assessmentHelper = AssessmentHelper()
13+
assessmentHelper.assessmentShowOnce({ true }, pass: nil);
14+
1215
//#-end-hidden-code
1316
/*:
1417
# Art of ASCII — Introduction to Digital Image Processing
@@ -32,7 +35,4 @@ delightful.
3235

3336
[Let's get started! 🏃‍♂️](@next)
3437
*/
35-
//#-hidden-code
36-
PlaygroundPage.current.assessmentStatus = .pass(message: nil)
37-
//#-end-hidden-code
3838

ArtOfAscii/Chapters/01-ArtOfAscii.playgroundchapter/Pages/02-HowImagesComposed.playgroundpage/main.swift

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,26 @@ import BookAPI
1212

1313
PlaygroundPage.current.needsIndefiniteExecution = true
1414

15-
func performCorrectnessCheck(matrix: [Double]) {
16-
if matrix == [
17-
1, 0, 0, 0,
18-
0, 1, 0, 0,
19-
0, 0, 1, 0,
20-
0, 0, 0, 1
21-
] {
22-
PlaygroundPage.current.assessmentStatus = .pass(
23-
message: """
24-
Congratulations, You've learnt how digital images composed.
25-
26-
Continue to [Preprocess Images for ASCII Art](@next)
27-
""")
28-
}
15+
var filterMatrix = [Double]()
16+
17+
let assessmentHelper = AssessmentHelper()
18+
func performCorrectnessCheck() {
19+
assessmentHelper.assessmentShowOnce({
20+
return filterMatrix == [
21+
1, 0, 0, 0,
22+
0, 1, 0, 0,
23+
0, 0, 1, 0,
24+
0, 0, 0, 1
25+
]
26+
}, pass: """
27+
Congratulations, You've learnt how digital images composed!
28+
29+
Continue to [Preprocess Images for ASCII Art](@next)
30+
"""
31+
);
2932
}
3033

34+
3135
//#-end-hidden-code
3236
/*:
3337
# Basics: How Images Composed
@@ -75,15 +79,13 @@ func applyRGBFilter(redEnabled: Bool,
7579

7680
// For most images, color components are arranged in the order of red, green, blue and alpha, per pixel basis.
7781
// For alpha channel, larger values means more opaque
78-
var filterMatrix: [Double] = [
82+
filterMatrix = [
7983
<#T##Red##Double#>, 0, 0, 0,
8084
0, <#T##Green##Double#>, 0, 0,
8185
0, 0, <#T##Blue##Double#>, 0,
8286
0, 0, 0, <#T##Alpha##Double#>
8387
]
8488
rawImage.multiplyByMatrix(matrix4x4: filterMatrix)
85-
86-
performCorrectnessCheck(matrix: filterMatrix)
8789
}
8890

8991
//#-end-editable-code
@@ -100,6 +102,7 @@ let eventListener = EventListener(proxy: remoteView) { message in
100102
if let destCGImage = rawImage.cgImage(bitmapInfo: destinationBitmapInfo) {
101103
remoteView?.send(EventMessage.imageProcessingResponse(image: UIImage(cgImage: destCGImage)).playgroundValue)
102104
}
105+
performCorrectnessCheck()
103106
default:
104107
break
105108
}

ArtOfAscii/Chapters/01-ArtOfAscii.playgroundchapter/Pages/03-GrayscaleHistogramEqualization.playgroundpage/main.swift

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,46 @@ import BookAPI
1212

1313
PlaygroundPage.current.needsIndefiniteExecution = true
1414

15+
var grayscaleMatrix = [Double]()
16+
17+
var histogram = [UInt]()
18+
var equalizationMap = [UInt8]()
19+
20+
let assessmentHelper = AssessmentHelper()
21+
func performCorrectnessCheck() {
22+
assessmentHelper.assessmentShowOnce({
23+
if !(grayscaleMatrix == [
24+
0.2126, 0.2126, 0.2126, 0,
25+
0.7152, 0.7152, 0.7152, 0,
26+
0.0722, 0.0722, 0.0722, 0,
27+
0, 0, 0, 1
28+
]) {
29+
return false
30+
}
31+
var equalizationMapCorrect = [UInt8](repeating: 0, count: 256)
32+
let pixelTotal = Double(histogram.reduce(0, +))
33+
var pixelCumulative: UInt = 0
34+
guard histogram.count >= 256 else {
35+
return false
36+
}
37+
for i in 0..<256 {
38+
pixelCumulative += histogram[i]
39+
let cumulativePixelFrequency: Double = Double(pixelCumulative) / pixelTotal
40+
let equalizedBrightness = cumulativePixelFrequency * 255.0
41+
equalizationMapCorrect[i] = UInt8(equalizedBrightness.rounded())
42+
}
43+
if !(equalizationMap == equalizationMapCorrect) {
44+
return false
45+
}
46+
return true
47+
}, pass: """
48+
Congratulations, You've accomplished preprocessing works with the knowledge just learned!
49+
50+
Continue to [The “ASCIIfication” Magic](@next)
51+
"""
52+
);
53+
}
54+
1555
//#-end-hidden-code
1656
/*:
1757
# Preprocessing: Grayscale, Histogram & Equalization
@@ -40,13 +80,13 @@ func applyGrayscaleFilter(rawImage: RawImage) {
4080
let coefficientRed = 0.2126
4181
let coefficientGreen = 0.7152
4282
let coefficientBlue = 0.0722
43-
var filterMatrix: [Double] = [
83+
grayscaleMatrix = [
4484
<#T##Red##Double#>, <#T##Red##Double#>, <#T##Red##Double#>, 0,
4585
<#T##Green##Double#>, <#T##Green##Double#>, <#T##Green##Double#>, 0,
4686
<#T##Blue##Double#>, <#T##Blue##Double#>, <#T##Blue##Double#>, 0,
4787
0, 0, 0, 1
4888
]
49-
rawImage.multiplyByMatrix(matrix4x4: filterMatrix)
89+
rawImage.multiplyByMatrix(matrix4x4: grayscaleMatrix)
5090
}
5191

5292
//#-end-editable-code
@@ -84,14 +124,15 @@ whole brightness range*, spreading out pixels that has intense frequency.
84124
*/
85125
//#-code-completion(everything, hide)
86126
//#-code-completion(literal, show, float, double, integer)
87-
//#-code-completion(identifier, show, pixelCumulative, pixelTotal, Double())
127+
//#-code-completion(identifier, show, pixelCumulative, pixelTotal)
88128
//#-editable-code
89129

90130
func applyHistogramEqualization(rawImage: RawImage) {
91-
guard let histogram = rawImage.calculateBrightnessHistogram() else {
131+
guard let unwrappedHistogram = rawImage.calculateBrightnessHistogram() else {
92132
return
93133
}
94-
var equalizationMap = [UInt8](repeating: 0, count: 256)
134+
histogram = unwrappedHistogram
135+
equalizationMap = [UInt8](repeating: 0, count: 256)
95136

96137
let pixelTotal = rawImage.format.pixelCount
97138
var pixelCumulative: UInt = 0
@@ -134,6 +175,7 @@ let eventListener = EventListener(proxy: remoteView) { message in
134175
if let destCGImage = rawImage.cgImage(bitmapInfo: destinationBitmapInfo) {
135176
remoteView?.send(EventMessage.imageProcessingResponse(image: UIImage(cgImage: destCGImage)).playgroundValue)
136177
}
178+
performCorrectnessCheck()
137179
default:
138180
break
139181
}

ArtOfAscii/Chapters/01-ArtOfAscii.playgroundchapter/Pages/04-Asciification.playgroundpage/main.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import BookAPI
1212

1313
PlaygroundPage.current.needsIndefiniteExecution = true
1414

15+
let assessmentHelper = AssessmentHelper()
16+
1517
//#-end-hidden-code
1618
/*:
1719
# The “ASCIIfication” Magic
@@ -27,9 +29,7 @@ Here is a **character map** built with font “Fira Code”, by arranging charac
2729

2830
*/
2931
//#-editable-code
30-
3132
let characterMapStr = "MWNXK0Okxdolc:;,'... "
32-
3333
//#-end-editable-code
3434
/*:
3535
## Resampling
@@ -73,7 +73,7 @@ func scaleImageForAsciification(rawImage: RawImage) -> RawImage? {
7373

7474
* Experiment:
7575
* Following code snippet generates an ASCII art by mapping pixels to characters according to their brightness level.
76-
* Run this code and tap the *ASCIIfy* button to see experience the magic, Feel free to tune all these parameters.
76+
* Run this code and tap the *ASCIIfy* button to see experience the magic, feel free to tune all these parameters!
7777
*/
7878
//#-editable-code
7979

@@ -126,6 +126,13 @@ let eventListener = EventListener(proxy: remoteView) { message in
126126
if let destImage = applyAsciification(rawImage: rawImage) {
127127
remoteView?.send(EventMessage.imageProcessingResponse(image: destImage).playgroundValue)
128128
}
129+
130+
assessmentHelper.assessmentShowOnce({ true },
131+
pass: """
132+
Congratulations! You've just created a wonderful ASCII Art and learned a lot about image processing.
133+
134+
Thanks for playing around! Let's stay tuned for WWDC20!
135+
""")
129136
default:
130137
break
131138
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// Copyright © 2020 Bunny Wong
3+
// Created by Bunny Wong on 2020/2/27.
4+
//
5+
6+
import UIKit
7+
import PlaygroundSupport
8+
9+
public class AssessmentHelper {
10+
11+
public typealias AssessmentFunc = () -> Bool
12+
13+
private var assessmentStatusShown = false
14+
15+
public init() {
16+
17+
}
18+
19+
public func assessmentShowOnce(_ assessmentFunc: AssessmentFunc, pass passMessage: String?) {
20+
guard !assessmentStatusShown else {
21+
return
22+
}
23+
if assessmentFunc() == true {
24+
assessmentStatusShown = true
25+
PlaygroundPage.current.assessmentStatus = .pass(message: passMessage)
26+
}
27+
}
28+
29+
}

ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/BaseViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public class BaseViewController: UIViewController,
123123
showcaseImageView.image = image
124124
}
125125

126-
private func setLoadingIndicatorHidden(_ hidden: Bool, animated: Bool) {
126+
func setLoadingIndicatorHidden(_ hidden: Bool, animated: Bool) {
127127
if loadingIndicatorView.isHidden == hidden {
128128
return
129129
}

ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/Chapters/01-ArtOfAscii/03-GrayscaleHistogramEqualization/Views/HistogramView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class HistogramView: UIView {
3939
override func awakeFromNib() {
4040
super.awakeFromNib()
4141

42-
self.backgroundColor = UIColor(white: 1.0, alpha: 0.3)
42+
self.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
4343
self.clipsToBounds = true
4444
self.layer.borderColor = UIColor.white.cgColor
4545
self.layer.borderWidth = 3.0

ArtOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/Chapters/01-ArtOfAscii/04-Asciification/AsciificationLiveViewController.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,13 @@ class AsciificationLiveViewController: BaseViewController, PhotoAlbumSavable {
5858
} else if shrinkButton.state == .selected {
5959
if let imageToShrink = preprocessButton.state == .selected ? preprocessedImage : sourceImage {
6060
let payload = EventMessage.shrinkingRequest(image: imageToShrink)
61-
send(payload.playgroundValue)
61+
send(payload.playgroundValue, showLoadingView: true)
6262
}
6363
} else if preprocessButton.state == .selected {
6464
if let preprocessedImage = preprocessedImage {
65+
setLoadingIndicatorHidden(false, animated: true)
6566
updateShowcaseImage(image: preprocessedImage)
67+
setLoadingIndicatorHidden(true, animated: true)
6668
}
6769
} else {
6870
if let image = sourceImage {

LiveViewTestApp/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import BookCore
1414
class AppDelegate: LiveViewHost.AppDelegate {
1515

1616
override func setUpLiveView() -> PlaygroundLiveViewable {
17-
return BookCore.instantiateLiveView(identifier: .introduction)
17+
return BookCore.instantiateLiveView(identifier: .asciification)
1818
}
1919

2020
override var liveViewConfiguration: LiveViewConfiguration {

0 commit comments

Comments
 (0)