Skip to content

Commit 0a989fd

Browse files
committed
Code cleanup.
1 parent 0f962c9 commit 0a989fd

File tree

14 files changed

+297
-327
lines changed

14 files changed

+297
-327
lines changed

FanOfAscii.xcodeproj/project.pbxproj

Lines changed: 163 additions & 171 deletions
Large diffs are not rendered by default.

FanOfAscii/Chapters/01-FanOfAscii.playgroundchapter/Manifest.plist

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<string>02-HowImagesComposed.playgroundpage</string>
1111
<string>03-GrayscaleHistogramEqualization.playgroundpage</string>
1212
<string>04-Asciification.playgroundpage</string>
13-
<string>05-MoreToPlay.playgroundpage</string>
1413
</array>
1514
</dict>
1615
</plist>

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

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Here is a **character map** built with font “Fira Code”, by arranging charac
2828
*/
2929
//#-editable-code
3030

31-
let characterMap = "MWNXK0Okxdolc:;,'... "
31+
let characterMapStr = "MWNXK0Okxdolc:;,'... "
3232

3333
//#-end-editable-code
3434
/*:
@@ -49,20 +49,20 @@ smooth result.
4949
//#-editable-code
5050

5151
// The aspect ratio of characters in the font “Fira Code”
52-
let ratio = 1.70667
52+
let characterAspectRatio = 0.5860
5353

54-
func calculateCharacterRows(rawImage: RawImage, charactersPerRow: Int) -> Int {
55-
let scaledHeight = Double(rawImage.format.height) * Double(charactersPerRow) / Double(rawImage.format.width)
56-
return Int((scaledHeight / ratio).rounded())
57-
}
54+
var charactersPerRow = 80
55+
var rowCount: Int!
5856

59-
let charactersPerRow = 80
60-
let characterRows = 0
57+
func calculateRowCount(imageFormat: ImageFormat, charactersPerRow: Int) -> Int {
58+
let scaledHeight = Double(charactersPerRow) / imageFormat.aspectRatio
59+
return Int((scaledHeight * characterAspectRatio).rounded())
60+
}
6161

6262
func scaleImageForAsciification(rawImage: RawImage) -> RawImage? {
63-
characterRows = calculateCharacterRows(rawImage: rawImage, charactersPerRow: charactersPerRow)
63+
rowCount = calculateRowCount(imageFormat: rawImage.format, charactersPerRow: charactersPerRow)
6464
// Scale the image to match the dimension of resulting ASCII art.
65-
return rawImage.scaled(width: charactersPerRow, height: characterRows)
65+
return rawImage.scaled(width: charactersPerRow, height: rowCount)
6666
}
6767

6868
//#-end-editable-code
@@ -72,41 +72,40 @@ func scaleImageForAsciification(rawImage: RawImage) -> RawImage? {
7272
### 🔨Mapping Pixels with Characters
7373

7474
* Experiment:
75-
* In this experiment, we'll build another filter to turn an image into grayscaled version, with consideration.
76-
* Try to read and complete the following code snippet. When you finish, run your code and tap the *Switch to
77-
Grayscale* button below the image to see whether it works.
75+
* 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.
7877
*/
7978
//#-editable-code
8079

8180
func applyAsciification(rawImage: RawImage) -> UIImage? {
82-
let brightnessLevels = Double(characterMap.count)
81+
let characterMap: [Character] = Array(characterMapStr)
82+
let maxMappedBrightness = Double(characterMap.count - 1)
8383
var asciificationResult: String = ""
84-
for y in 0..<characterRows {
84+
85+
for y in 0..<rowCount {
8586
for x in 0..<charactersPerRow {
8687
if var pixel = rawImage.pixelAt(x: x, y: y) {
87-
let mappedBrightnessValue = pixel.brightness / 255.0 * (brightnessLevels - 1)
88-
asciificationResult.append(Array(characterMap)[Int(mappedBrightnessValue.rounded())])
88+
let mappedBrightnessValue = pixel.brightness / 255.0 * maxMappedBrightness
89+
asciificationResult.append(characterMap[Int(mappedBrightnessValue.rounded())])
8990
}
9091
}
9192
asciificationResult += "\n"
9293
}
93-
return RawImage.renderAsciifiedImage(
94+
95+
return AsciiArtRenderer.renderAsciifiedImage(
9496
asciificationResult,
95-
font: FiraCode.bold.rawValue,
96-
size: 14,
97-
charactersInRow: charactersPerRow,
98-
rows: characterRows,
99-
characterRatio: ratio)
97+
fontName: FontResourceProvider.FiraCode.bold.rawValue,
98+
size: 14.0,
99+
foreground: UIColor.black,
100+
background: UIColor.white,
101+
charactersPerRow: charactersPerRow,
102+
rows: rowCount,
103+
characterAspectRatio: characterAspectRatio)
100104
}
101105

102106
//#-end-editable-code
103-
/*:
104-
* Note:
105-
In this code snippet, we transform the image by multiplying it with a custom filter matrix. If you're not familiar
106-
with limier algebra, the following figure will explain how this transform matrix works.
107-
*/
108-
////#-hidden-code
109-
FiraCode.registerFont()
107+
//#-hidden-code
108+
FontResourceProvider.FiraCode.register()
110109

111110
let remoteView = remoteViewAsLiveViewProxy()
112111
let eventListener = EventListener(proxy: remoteView) { message in
@@ -131,4 +130,4 @@ let eventListener = EventListener(proxy: remoteView) { message in
131130
break
132131
}
133132
}
134-
////#-end-hidden-code
133+
//#-end-hidden-code

FanOfAscii/Chapters/01-FanOfAscii.playgroundchapter/Pages/05-MoreToPlay.playgroundpage/LiveView.swift

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

FanOfAscii/Chapters/01-FanOfAscii.playgroundchapter/Pages/05-MoreToPlay.playgroundpage/Manifest.plist

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

FanOfAscii/Chapters/01-FanOfAscii.playgroundchapter/Pages/05-MoreToPlay.playgroundpage/main.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// Copyright © 2020 Bunny Wong
3+
// Created by Bunny Wong on 2020/2/20.
4+
//
5+
6+
import UIKit
7+
8+
public class AsciiArtRenderer {
9+
10+
public static func renderAsciifiedImage(_ string: String,
11+
fontName: String,
12+
size: CGFloat,
13+
foreground: UIColor,
14+
background: UIColor,
15+
charactersPerRow: Int,
16+
rows: Int,
17+
characterAspectRatio: Double) -> UIImage {
18+
let characterWidth = size * CGFloat(characterAspectRatio)
19+
let characterHeight = size
20+
let drawingRect = CGRect(
21+
origin: CGPoint(x: 0, y: 0),
22+
size: CGSize(width: characterWidth * CGFloat(charactersPerRow), height: characterHeight * CGFloat(rows)))
23+
24+
let renderer = UIGraphicsImageRenderer(size: drawingRect.size)
25+
let img = renderer.image { ctx in
26+
background.setFill()
27+
ctx.fill(drawingRect)
28+
29+
let paragraphStyle = NSMutableParagraphStyle()
30+
paragraphStyle.alignment = .left
31+
paragraphStyle.lineSpacing = 0.0
32+
paragraphStyle.maximumLineHeight = size
33+
paragraphStyle.lineBreakMode = .byClipping
34+
let attrs = [
35+
NSAttributedString.Key.font: UIFont(name: fontName, size: size)!,
36+
NSAttributedString.Key.foregroundColor: foreground,
37+
NSAttributedString.Key.paragraphStyle: paragraphStyle
38+
]
39+
string.draw(
40+
with: drawingRect,
41+
options: .usesLineFragmentOrigin,
42+
attributes: attrs,
43+
context: nil)
44+
}
45+
return img
46+
}
47+
48+
}

FanOfAscii/Modules/BookAPI.playgroundmodule/Sources/Core/FireCode.swift

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Copyright © 2020 Bunny Wong
3+
// Created by Bunny Wong on 2020/2/20.
4+
//
5+
6+
import Foundation
7+
import CoreText
8+
9+
public protocol Font {
10+
11+
static var resourceName: String { get }
12+
static var resourceExtension: String { get }
13+
14+
static func register()
15+
16+
}
17+
18+
public extension Font {
19+
20+
static func register() {
21+
guard let fontURL = Bundle.main.url(forResource: resourceName, withExtension: resourceExtension) else {
22+
return
23+
}
24+
CTFontManagerRegisterFontsForURL(fontURL as CFURL, CTFontManagerScope.process, nil)
25+
}
26+
27+
}
28+
29+
public class FontResourceProvider {
30+
31+
public enum FiraCode: String, Font {
32+
33+
case light = "FiraCode-Light"
34+
case retina = "FiraCode-Light_Retina"
35+
case bold = "FiraCode-Light_Bold"
36+
case medium = "FiraCode-Light_Medium"
37+
case regular = "FiraCode-Light_Regular"
38+
39+
public static var resourceName: String {
40+
return "FiraCode-VF"
41+
}
42+
public static var resourceExtension: String {
43+
return "ttf"
44+
}
45+
46+
}
47+
48+
}
49+

FanOfAscii/Modules/BookCore.playgroundmodule/Sources/Core/LiveViewSupport.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ public enum LiveViewIdentifier: String {
1111
case howImagesComposed
1212
case grayscaleHistogramEqualization
1313
case asciification
14-
case moreToPlay
1514
}
1615

1716
public func instantiateLiveView(identifier: LiveViewIdentifier) -> PlaygroundLiveViewable {

FanOfAscii/Modules/BookCore.playgroundmodule/Sources/Core/RawImage.swift

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import UIKit
77
import Accelerate
8-
import CoreText
98

109
public struct Pixel {
1110

@@ -34,6 +33,10 @@ public class ImageFormat {
3433
return width * height
3534
}()
3635

36+
public lazy var aspectRatio: Double = {
37+
return Double(width) / Double(height)
38+
}()
39+
3740
public init(cgImage: CGImage) {
3841
self.width = cgImage.width
3942
self.height = cgImage.height
@@ -102,35 +105,6 @@ public class RawImage {
102105
return context.makeImage()
103106
}
104107

105-
public static func renderAsciifiedImage(_ string: String, font: String, size: CGFloat, charactersInRow: Int, rows: Int, characterRatio: Double) -> UIImage {
106-
let characterWidth = size / CGFloat(characterRatio)
107-
let characterHeight = size
108-
let drawingRect = CGRect(
109-
origin: CGPoint(x: 0, y: 0),
110-
size: CGSize(width: characterWidth * CGFloat(charactersInRow), height: characterHeight * CGFloat(rows)))
111-
let renderer = UIGraphicsImageRenderer(size: drawingRect.size)
112-
let img = renderer.image { ctx in
113-
UIColor.white.setFill()
114-
ctx.fill(drawingRect)
115-
116-
let paragraphStyle = NSMutableParagraphStyle()
117-
paragraphStyle.alignment = .left
118-
paragraphStyle.lineSpacing = 0.0
119-
paragraphStyle.maximumLineHeight = size
120-
paragraphStyle.lineBreakMode = .byClipping
121-
let attrs = [
122-
NSAttributedString.Key.font: UIFont(name: font, size: size)!,
123-
NSAttributedString.Key.paragraphStyle: paragraphStyle
124-
]
125-
string.draw(
126-
with: drawingRect,
127-
options: .usesLineFragmentOrigin,
128-
attributes: attrs,
129-
context: nil)
130-
}
131-
return img
132-
}
133-
134108
public func pixelAt(x: Int, y: Int) -> Pixel? {
135109
if x < 0 || x > format.width || y < 0 || y > format.height {
136110
return nil

FanOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/Chapters/01-FanOfAscii/01-Introduction/IntroductionLiveViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
import Foundation
77

8-
class IntroductionLiveViewController {
8+
class IntroductionLiveViewController: BaseViewController {
99

1010
}

FanOfAscii/Modules/BookCore.playgroundmodule/Sources/UserInterface/Chapters/01-FanOfAscii/05-MoreToPlay/MoreToPlayLiveViewController.swift

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

FanOfAscii/PrivateResources/LiveView.storyboard

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
1010
</dependencies>
1111
<scenes>
12-
<!--View Controller-->
12+
<!--Base View Controller-->
1313
<scene sceneID="Jtu-W4-dxd">
1414
<objects>
15-
<viewController storyboardIdentifier="introduction" id="CJm-3e-I7M" sceneMemberID="viewController">
15+
<viewController storyboardIdentifier="introduction" id="CJm-3e-I7M" customClass="BaseViewController" customModule="BookCore" sceneMemberID="viewController">
1616
<view key="view" contentMode="scaleToFill" id="GcL-rA-cmv">
1717
<rect key="frame" x="0.0" y="0.0" width="810" height="1080"/>
1818
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -292,33 +292,6 @@
292292
</objects>
293293
<point key="canvasLocation" x="196" y="787"/>
294294
</scene>
295-
<!--View Controller-->
296-
<scene sceneID="Qnk-Qq-r88">
297-
<objects>
298-
<viewController storyboardIdentifier="moreToPlay" id="aAC-EE-NIM" sceneMemberID="viewController">
299-
<view key="view" contentMode="scaleToFill" id="GuK-2t-njf">
300-
<rect key="frame" x="0.0" y="0.0" width="810" height="1080"/>
301-
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
302-
<subviews>
303-
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="More to play" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Nhd-e9-pZD">
304-
<rect key="frame" x="357.5" y="529.5" width="95" height="21"/>
305-
<fontDescription key="fontDescription" type="system" pointSize="17"/>
306-
<nil key="textColor"/>
307-
<nil key="highlightedColor"/>
308-
</label>
309-
</subviews>
310-
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
311-
<constraints>
312-
<constraint firstItem="Nhd-e9-pZD" firstAttribute="centerX" secondItem="GuK-2t-njf" secondAttribute="centerX" id="4YR-1c-NPl"/>
313-
<constraint firstItem="Nhd-e9-pZD" firstAttribute="centerY" secondItem="GuK-2t-njf" secondAttribute="centerY" id="Jts-vt-iz8"/>
314-
</constraints>
315-
<viewLayoutGuide key="safeArea" id="gRl-fP-bh6"/>
316-
</view>
317-
</viewController>
318-
<placeholder placeholderIdentifier="IBFirstResponder" id="mN9-db-Rho" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
319-
</objects>
320-
<point key="canvasLocation" x="587" y="788"/>
321-
</scene>
322295
<!--imagePickerViewController-->
323296
<scene sceneID="NPE-OX-idZ">
324297
<objects>

0 commit comments

Comments
 (0)