Skip to content

Commit

Permalink
fix scaling, optionalize API
Browse files Browse the repository at this point in the history
  • Loading branch information
dmrschmidt committed Feb 14, 2017
1 parent baa5e4a commit 1d4ec25
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 42 deletions.
2 changes: 1 addition & 1 deletion DSWaveformImage.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "DSWaveformImage"
s.version = "4.0.0"
s.version = "5.0.0"
s.summary = "generate waveform images from audio files in iOS"
s.description = <<-DESC
DSWaveformImageDrawer and DSWaveformImageView generate waveform images of audio files.
Expand Down
46 changes: 31 additions & 15 deletions DSWaveformImage/DSWaveformImage/WaveformImageDrawer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,41 @@ public struct WaveformImageDrawer {
public func waveformImage(from waveform: Waveform, with configuration: WaveformConfiguration) -> UIImage? {
let scaledSize = CGSize(width: configuration.size.width * configuration.scale,
height: configuration.size.height * configuration.scale)
let scaledConfiguration = WaveformConfiguration(color: configuration.color, style: configuration.style,
position: configuration.position, size: scaledSize,
scale: configuration.scale)
let scaledConfiguration = WaveformConfiguration(size: scaledSize,
color: configuration.color,
backgroundColor: configuration.backgroundColor,
style: configuration.style,
position: configuration.position,
scale: configuration.scale,
paddingFactor: configuration.paddingFactor)
return render(waveform: waveform, with: scaledConfiguration)
}

public func waveformImage(fromAudio audioAsset: AVURLAsset,
color: UIColor,
style: WaveformStyle,
position: WaveformPosition,
size: CGSize,
scale: CGFloat) -> UIImage? {
color: UIColor = UIColor.black,
backgroundColor: UIColor = UIColor.white,
style: WaveformStyle = .gradient,
position: WaveformPosition = .middle,
scale: CGFloat = UIScreen.main.scale,
paddingFactor: CGFloat? = nil) -> UIImage? {
guard let waveform = Waveform(audioAsset: audioAsset) else { return nil }
let configuration = WaveformConfiguration(color: color, style: style, position: position, size: size, scale: scale)
let configuration = WaveformConfiguration(size: size, color: color, backgroundColor: backgroundColor, style: style,
position: position, scale: scale, paddingFactor: paddingFactor)
return waveformImage(from: waveform, with: configuration)
}

public func waveformImage(fromAudioAt audioAssetURL: URL,
color: UIColor,
style: WaveformStyle,
position: WaveformPosition,
size: CGSize,
scale: CGFloat) -> UIImage? {
color: UIColor = UIColor.black,
backgroundColor: UIColor = UIColor.white,
style: WaveformStyle = .gradient,
position: WaveformPosition = .middle,
scale: CGFloat = UIScreen.main.scale,
paddingFactor: CGFloat? = nil) -> UIImage? {
let audioAsset = AVURLAsset(url: audioAssetURL)
return waveformImage(fromAudio: audioAsset, color: color, style: style, position: position, size: size, scale: scale)
return waveformImage(fromAudio: audioAsset, size: size, color: color, backgroundColor: backgroundColor, style: style,
position: position, scale: scale, paddingFactor: paddingFactor)
}
// swiftlint:enable function_parameter_count
}
Expand All @@ -47,11 +57,12 @@ fileprivate extension WaveformImageDrawer {
}

private func graphImage(from samples: [Float], with configuration: WaveformConfiguration) -> UIImage? {
UIGraphicsBeginImageContext(configuration.size)
UIGraphicsBeginImageContextWithOptions(configuration.size, true, configuration.scale)
let context = UIGraphicsGetCurrentContext()!
context.setAllowsAntialiasing(true)
context.setShouldAntialias(true)

drawBackground(on: context, with: configuration)
drawGraph(from: samples, on: context, with: configuration)

let graphImage = UIGraphicsGetImageFromCurrentImageContext()
Expand All @@ -60,13 +71,18 @@ fileprivate extension WaveformImageDrawer {
return graphImage
}

private func drawBackground(on context: CGContext, with configuration: WaveformConfiguration) {
context.setFillColor(configuration.backgroundColor.cgColor)
context.fill(CGRect(origin: CGPoint.zero, size: configuration.size))
}

private func drawGraph(from samples: [Float],
on context: CGContext,
with configuration: WaveformConfiguration) {
let graphRect = CGRect(origin: CGPoint.zero, size: configuration.size)
let graphCenter = graphRect.size.height / 2.0
let positionAdjustedGraphCenter = graphCenter + CGFloat(configuration.position.rawValue) * graphCenter
let verticalPaddingDivisor = CGFloat(configuration.position == .middle ? 2.5 : 1.5) // 2 = 50 % of height
let verticalPaddingDivisor = configuration.paddingFactor ?? CGFloat(configuration.position == .middle ? 2.5 : 1.5)
let drawMappingFactor = graphRect.size.height / verticalPaddingDivisor
let minimumGraphAmplitude: CGFloat = 1 // we want to see at least a 1pt line for silence

Expand Down
40 changes: 38 additions & 2 deletions DSWaveformImage/DSWaveformImage/WaveformImageTypes.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,65 @@
import AVFoundation

/**
Position of the drawn waveform:
- **top**: Draws the waveform at the top of the image, such that only the bottom 50% are visible.
- **top**: Draws the waveform in the middle the image, such that the entire waveform is visible.
- **bottom**: Draws the waveform at the bottom of the image, such that only the top 50% are visible.
*/
public enum WaveformPosition: Int {
case top = -1
case middle = 0
case bottom = 1
}

/**
Style of the waveform which is used during drawing:
- **filled**: Use solid color for the waveform.
- **gradient**: Use gradient based on color for the waveform.
- **striped**: Use striped filling based on color for the waveform.
*/
public enum WaveformStyle: Int {
case filled = 0
case gradient
case striped
}

/// Allows customization of the waveform output image.
public struct WaveformConfiguration {
/// Desired output size of the waveform image, works together with scale.
let size: CGSize

/// Color of the waveform, defaults to black.
let color: UIColor

/// Background color of the waveform, defaults to white.
let backgroundColor: UIColor

/// Waveform drawing style, defaults to .gradient.
let style: WaveformStyle

/// Waveform drawing position, defaults to .middle.
let position: WaveformPosition
let size: CGSize

/// Scale to be applied to the image, defaults to main screen's scale.
let scale: CGFloat

public init(color: UIColor, style: WaveformStyle, position: WaveformPosition, size: CGSize, scale: CGFloat) {
/// Optional padding or vertical shrinking factor for the waveform.
let paddingFactor: CGFloat?

public init(size: CGSize,
color: UIColor = UIColor.black,
backgroundColor: UIColor = UIColor.white,
style: WaveformStyle = .gradient,
position: WaveformPosition = .middle,
scale: CGFloat = UIScreen.main.scale,
paddingFactor: CGFloat? = nil) {
self.color = color
self.backgroundColor = UIColor.white
self.style = style
self.position = position
self.size = size
self.scale = scale
self.paddingFactor = paddingFactor
}
}
4 changes: 2 additions & 2 deletions DSWaveformImage/DSWaveformImage/WaveformImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public class WaveformImageView: UIImageView {
fileprivate extension WaveformImageView {
func updateWaveform() {
guard let audioURL = waveformAudioURL else { return }
image = waveformImageDrawer.waveformImage(fromAudioAt: audioURL, color: waveformColor, style: waveformStyle,
position: waveformPosition, size: bounds.size,
image = waveformImageDrawer.waveformImage(fromAudioAt: audioURL, size: bounds.size, color: waveformColor,
style: waveformStyle, position: waveformPosition,
scale: UIScreen.main.scale)
}
}
2 changes: 1 addition & 1 deletion DSWaveformImage/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>4.0.0</string>
<string>4.1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
2 changes: 1 addition & 1 deletion DSWaveformImageExample/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>4.0.0</string>
<string>4.1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
Expand Down
23 changes: 9 additions & 14 deletions DSWaveformImageExample/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,26 @@ class ViewController: UIViewController {
let waveformImageDrawer = WaveformImageDrawer()
let audioURL = Bundle.main.url(forResource: "example_sound_2", withExtension: "m4a")!
let topWaveformImage = waveformImageDrawer.waveformImage(fromAudioAt: audioURL,
color: UIColor.black,
style: .striped,
position: .top,
size: middleWaveformView.bounds.size,
scale: UIScreen.main.scale)
style: .striped,
position: .top)
topWaveformView.image = topWaveformImage

middleWaveformView.waveformColor = UIColor.red
middleWaveformView.waveformStyle = .gradient
middleWaveformView.waveformAudioURL = audioURL

let bottomWaveformImage = waveformImageDrawer.waveformImage(fromAudioAt: audioURL,
color: UIColor.blue,
style: .filled,
position: .middle,
size: middleWaveformView.bounds.size,
scale: UIScreen.main.scale)
size: middleWaveformView.bounds.size,
color: UIColor.blue,
style: .filled,
paddingFactor: 5.0)
bottomWaveformView.image = bottomWaveformImage

let waveform = Waveform(audioAssetURL: audioURL)!
let configuration = WaveformConfiguration(color: UIColor.blue,
let configuration = WaveformConfiguration(size: lastWaveformView.bounds.size,
color: UIColor.blue,
style: .striped,
position: .bottom,
size: lastWaveformView.bounds.size,
scale: UIScreen.main.scale)
position: .bottom)
lastWaveformView.image = UIImage(waveform: waveform, configuration: configuration)
}
}
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ creating an instance of `Waveform`.
Installation
------------

* use carthage: `github "dmrschmidt/DSWaveformImage" ~> 4.0`
* use cocoapods: `pod 'DSWaveformImage', '~> 4.0'`
* use carthage: `github "dmrschmidt/DSWaveformImage" ~> 5.0`
* use cocoapods: `pod 'DSWaveformImage', '~> 5.0'`
* or add the DSWaveformImage folder directly into your project.

Usage
Expand All @@ -24,10 +24,11 @@ To create a `UIImage` using `WaveformImageDrawer`:
let waveformImageDrawer = WaveformImageDrawer()
let audioURL = Bundle.main.url(forResource: "example_sound", withExtension: "m4a")!
let topWaveformImage = waveformImageDrawer.waveformImage(fromAudioAt: audioURL,
size: UIScreen.main.bounds.size,
color: UIColor.black,
backgroundColor: UIColor.black,
style: .filled,
position: .top,
size: UIScreen.main.bounds.size,
scale: UIScreen.main.scale)
```

Expand All @@ -37,11 +38,12 @@ To create a `UIImage` using a `UIImage` extension:
```swift
let audioURL = Bundle.main.url(forResource: "example_sound", withExtension: "m4a")!
let waveform = Waveform(audioAssetURL: audioURL)!
let configuration = WaveformConfiguration(color: UIColor.blue,
let configuration = WaveformConfiguration(size: UIScreen.main.bounds.size,
color: UIColor.blue,
style: .striped,
position: .middle,
size: UIScreen.main.bounds.size,
scale: UIScreen.main.scale)
scale: UIScreen.main.scale,
paddingFactor: 4.0)
let waveformImage = UIImage(waveform: waveform, configuration: configuration)
```

Expand Down

0 comments on commit 1d4ec25

Please sign in to comment.