Convert an array to matrix to find adjacent elements iOS swift - ios

Convert this below array into matrix
Array
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
Matrix
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
To find adjacent points in uniderectional like an below image
Expected output
(0,1) (0,6)
(1,2) (1,7)
(2,3) (2,8)
(3,4) (3,9)
(4,5) (4,10)
(5,11)
(6,7) (6,12)
(7,8) (7,13)
(8,9) (8,14)
(9,10) (9,15)
(10,11) (10,16)
(11,17)
(12,13)
(13,14)
(14,15)
(15,16)
(16,17)
My failed approach
for i in 0..<pointsArray.count-1{
if (i+1)%6 == 0 && i != 0{
print("Connection (\(i),\(i+6))")
nodesArray[i].addConnection(to: nodesArray[i+6], bidirectional: true, weight: 1)
}
if i>=pointsArray.count-6{
print("Connection (\(i),\(i+1))")
nodesArray[i].addConnection(to: nodesArray[i+1], bidirectional: true, weight: 1)
}
else{
print("Connection (\(i),\(i+1)) (\(i),\(i+6))")
nodesArray[i].addConnection(to: nodesArray[i+1], bidirectional: true, weight: 1)
nodesArray[i].addConnection(to: nodesArray[i+6], bidirectional: true, weight: 1)
}
}
Output:
Connection (0,1) (0,6)
Connection (1,2) (1,7)
Connection (2,3) (2,8)
Connection (3,4) (3,9)
Connection (4,5) (4,10)
Connection (5,11)
Connection (5,6) (5,11)
Connection (6,7) (6,12)
Connection (7,8) (7,13)
Connection (8,9) (8,14)
Connection (9,10) (9,15)
Connection (10,11) (10,16)
Connection (11,17)
Connection (11,12) (11,17)
Connection (12,13)
Connection (13,14)
Connection (14,15)
Connection (15,16)
Connection (16,17)

In the desired output, I guess that it's missing (9,15), (10,11), (10,16) and that (10,15) isn't valid.
If we think about your desired output, we notice something.
Let's name width = 6, it's the "width" of your matrix.
We see the pattern:
(value, value + 1), (value, value + width)
With some excluded tests: does (value + width) exists ? And we are not at the end of the width.
Let's, with a little reduce method:
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
let width = 6
let tuples = ptsArray.indices.reduce(into: [(Int, Int)]()) { partialResult, anIndex in
if ptsArray.count > anIndex.advanced(by: 1) && anIndex % width != width - 1 {
let newValue = (ptsArray[anIndex], ptsArray[anIndex.advanced(by: 1)])
print(newValue)
partialResult.append(newValue)
}
if ptsArray.count > anIndex.advanced(by: width) {
let newValue = (ptsArray[anIndex], ptsArray[anIndex.advanced(by: width)])
print(newValue)
partialResult.append(newValue)
}
return
}
print(tuples)
I used "index", because in fact, points are in order here, but it could be any value, no? So let's use the index instead.
So, with something a little more generic:
extension Array {
func coupling(with width: Int) -> [(Element, Element)] {
let couples = indices.reduce(into: [(Element, Element)]()) { partialResult, anIndex in
if count > anIndex.advanced(by: 1) && anIndex % width != width - 1 {
let newValue = (self[anIndex], self[anIndex.advanced(by: 1)])
partialResult.append(newValue)
}
if count > anIndex.advanced(by: width) {
let newValue = (self[anIndex], self[anIndex.advanced(by: width)])
partialResult.append(newValue)
}
return
}
return couples
}
}
Use:
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
let tuples2 = ptsArray. coupling(with: width)
print(tuples2)
let lettersArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", "Q", "R"]
let tuples3 = lettersArray. coupling(with: width)
print(tuples3)

Another approach - convert your ptsArray into a 2-D matrix:
var matrix: [[Int]] = []
let numCols: Int = 6
var numRows: Int = 0
let ptsArray: [Int] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
for i in stride(from: 0, to: ptsArray.count, by: numCols) {
// make sure we don't exceed the array limit
if ptsArray.count >= i+numCols {
matrix.append(Array(ptsArray[i..<i+numCols]))
}
}
numRows = matrix.count
You can now get the right and down values (if they exist) like this:
func getPair2D(_ n: Int) -> (Int?, Int?) {
let thisRow = n / numCols
let thisCol = n % numCols
let numToRight = thisCol < numCols-1 ? matrix[thisRow][thisCol+1] : nil
let numToDown = thisRow < numRows-1 ? matrix[thisRow+1][thisCol] : nil
return (numToRight, numToDown)
}
and this will print out the results:
for i in 0..<ptsArray.count {
let (n1, n2) = getPair2D(i)
var str = ""
if let n1 = n1 {
str += "(\(i), \(n1))"
}
if let n2 = n2 {
if !str.isEmpty { str += " " }
str += "(\(i), \(n2))"
}
print(str)
}
Here's a simple view controller that let's you tap any number to show the "right and down" matches:
class MatrixVC: UIViewController {
var matrix: [[Int]] = []
var views: [UIView] = []
let numCols: Int = 6
var numRows: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let ptsArray: [Int] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
for i in stride(from: 0, to: ptsArray.count, by: numCols) {
if ptsArray.count >= i+numCols {
matrix.append(Array(ptsArray[i..<i+numCols]))
}
}
numRows = matrix.count
let oStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.distribution = .fillEqually
v.spacing = 2
return v
}()
var n = 0
for r in 0..<numRows {
let rStack: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.distribution = .fillEqually
v.spacing = 2
return v
}()
for c in 0..<numCols {
let v = UILabel()
v.textAlignment = .center
v.text = "\(ptsArray[n])"
v.isUserInteractionEnabled = true
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
v.addGestureRecognizer(t)
rStack.addArrangedSubview(v)
views.append(v)
if c < numCols-1 {
let iv = UIImageView(image: UIImage(systemName: "arrow.right"))
rStack.addArrangedSubview(iv)
}
n += 1
}
oStack.addArrangedSubview(rStack)
if r < numRows-1 {
let rStack: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.distribution = .fillEqually
v.spacing = 2
return v
}()
for c in 0..<numCols {
let iv = UIImageView(image: UIImage(systemName: "arrow.down"))
rStack.addArrangedSubview(iv)
if c < numCols-1 {
let v = UIView()
rStack.addArrangedSubview(v)
}
}
oStack.addArrangedSubview(rStack)
}
}
oStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(oStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
oStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
oStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
oStack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
oStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
}
#objc func gotTap(_ g: UITapGestureRecognizer) {
guard let v = g.view as? UILabel,
let t = v.text,
let n = Int(t)
else { return }
// if the tapped label is yellow, let's just deselect all
let deselecting: Bool = views[n].backgroundColor == .yellow
views.forEach { $0.backgroundColor = .clear }
if deselecting {
return()
}
views[n].backgroundColor = .yellow
let (n1, n2) = getPair2D(n)
if let n1 = n1 {
views[n1].backgroundColor = .yellow
}
if let n2 = n2 {
views[n2].backgroundColor = .yellow
}
}
func getPair2D(_ n: Int) -> (Int?, Int?) {
let thisRow = n / numCols
let thisCol = n % numCols
let numToRight = thisCol < numCols-1 ? matrix[thisRow][thisCol+1] : nil
let numToDown = thisRow < numRows-1 ? matrix[thisRow+1][thisCol] : nil
return (numToRight, numToDown)
}
}
It looks like this:
Tapping any number will highlight the pair:
Tapping a "highlighted" number will "un-highlight" all numbers.

Related

Swiftchars - bars chart overlap after specific number of points

How can I specify min space between bars in bar chart using SwiftChars library ?
Here is my code sample for using SwiftCharts to display bars chart:
// xAxis
let labelSettings = ChartLabelSettings(font: .systemFont(ofSize: 13.0), fontColor: .aiduBlue)
var xValues = [ChartAxisValue]()
xValues.append(ChartAxisValueString(order: -1))
for (index, point) in barsDataSource.enumerated() {
let dateString = DateFormatter.shortDayOfWeekDayOnTwoLinesFormatter.string(from: point.departureDate)
xValues.append(ChartAxisValueString(dateString, order: index, labelSettings: labelSettings))
}
xValues.append(ChartAxisValueString(order: xValues.count - 1))
let xModel = ChartAxisModel(axisValues: xValues,
lineColor: .aiduSkyBlue,
axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings))
// yAxis
let yAxisMinSpaceBetweenPoints: CGFloat = 10.0
let yAxisTopBottomMargin = (((barsMaxPrice - barsMinPrice) / Double(barsDataSource.count)) + Double(yAxisMinSpaceBetweenPoints)) + 10
let yAxisGenerator = ChartAxisValuesGeneratorNice(minValue: barsMinPrice - yAxisTopBottomMargin,
maxValue: barsMaxPrice + yAxisTopBottomMargin,
preferredDividers: 1,
minSpace: yAxisMinSpaceBetweenPoints,
maxTextSize: CGFloat.greatestFiniteMagnitude,
multiplierUpdateMode: .nice)
let yLabelsGenerator = ChartAxisLabelsGeneratorFunc {scalar in
return ChartAxisLabel(text: "", settings: ChartLabelSettings())
}
let yModel = ChartAxisModel(lineColor: UIColor.white.withAlphaComponent(0),
firstModelValue: barsMinPrice,
lastModelValue: barsMaxPrice,
axisTitleLabels: [],
axisValuesGenerator: yAxisGenerator,
labelsGenerator: yLabelsGenerator)
// Char Bars layer
let frame = chartFrame(containerView.bounds)
let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings,
chartFrame: frame,
xModel: xModel,
yModel: yModel)
let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)
let barsModels: [ChartBarModel] = barsDataSource.enumerated().flatMap { index, item in
[
ChartBarModel(constant: ChartAxisValueInt(index),
axisValue1: ChartAxisValueDouble(0),
axisValue2: ChartAxisValueDouble(item.price),
bgColor: barColor(price: item.price, minPrice: barsMinPrice))
]
}
let chartBarSettings = ChartBarViewSettings(animDuration: 0,
animDelay: 0,
cornerRadius: 0,
roundedCorners: .allCorners,
selectionViewUpdater: nil,
delayInit: false)
let chartBarsLayer = ChartBarsLayer(xAxis: xAxisLayer.axis,
yAxis: yAxisLayer.axis,
bars: barsModels,
horizontal: false,
barWidth: 40,
settings: chartBarSettings,
mode: .translate,
tapHandler: { [weak self] (tappedBar) in
self?.chartBarTapHandler(tappedBar: tappedBar)
}, viewGenerator: { [weak self] (p1, p2, barWidth, color, settings, model, index) -> ChartPointViewBar in
var barBGColor = color
if let s = self, let lastTappedBarModel = s.lastTappedBarModel {
let currentBarModel = s.dataSource[index]
barBGColor = currentBarModel.departureDate == lastTappedBarModel.departureDate && currentBarModel.duration == lastTappedBarModel.duration ? s.barSelectionBgColor : color
}
let view = ChartPointViewBar(p1: p1, p2: p2, width: barWidth, bgColor: barBGColor, settings: settings)
return view
})
// Price labels layer
let labelToBarSpace: Double = 20
let labelChartPoints = barsModels.map { bar in
ChartPoint(x: bar.constant, y: bar.axisValue2.copy(bar.axisValue2.scalar + labelToBarSpace))
}
let priceLabelsLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis,
yAxis: yAxisLayer.axis,
chartPoints: labelChartPoints,
viewGenerator: {(chartPointModel, layer, chart) -> UIView? in
let label = HandlingLabel()
label.text = PriceFormatter.string(fromPrice: Float(chartPointModel.chartPoint.y.scalar - labelToBarSpace))
label.font = .boldSystemFont(ofSize: 10.0)
label.textColor = UIColor.aiduBlue
label.sizeToFit()
let pos = chartPointModel.chartPoint.y.scalar > 0
label.center = CGPoint(x: chartPointModel.screenLoc.x, y: pos ? innerFrame.origin.y : innerFrame.origin.y + innerFrame.size.height)
label.alpha = 0
label.isUserInteractionEnabled = false
label.movedToSuperViewHandler = {[weak label] in
label?.alpha = 1
label?.center.y = chartPointModel.screenLoc.y
}
return label
}, displayDelay: 0, mode: .translate)
return Chart(
frame: frame,
innerFrame: innerFrame,
settings: chartSettings,
layers: [
xAxisLayer,
yAxisLayer,
chartBarsLayer,
priceLabelsLayer
]
)
private var chartSettings: ChartSettings {
var chartSettings = ChartSettings()
chartSettings.leading = 2
chartSettings.top = 2
chartSettings.trailing = 2
chartSettings.bottom = 2
chartSettings.axisStrokeWidth = 0.4
chartSettings.spacingBetweenAxesX = 2
chartSettings.spacingBetweenAxesY = 2
chartSettings.labelsSpacing = 10
chartSettings.labelsToAxisSpacingY = 0
chartSettings.spacingBetweenAxesY = 0
chartSettings.axisTitleLabelsToLabelsSpacing = 0
chartSettings.zoomPan.panEnabled = true
chartSettings.zoomPan.zoomEnabled = false
chartSettings.zoomPan.maxZoomX = 3
chartSettings.zoomPan.minZoomX = 3
chartSettings.zoomPan.minZoomY = 1
chartSettings.zoomPan.maxZoomY = 1
return chartSettings
}
When data source contains around (10 for ex) points, chart working without overlapping, but without fixed space between bars if you changed (increase/decrease) data source:
When data source contains around (35 for ex) points, bars overlapped:
SwiftCharts version 0.6.5
Swift version 5
Finally I found solution:
I had to set the minZoomX and maxZoomX (in chart settings) with fixed value which the number of pages for the chart (or number of scrollable area than the original width).
why x ? because I want chart to scroll horizontally.
here is code:
let barWidth: CGFloat = 30.0
let spaceBetweenBars: CGFloat = 80.0
let zoomXValue = CGFloat(barsDataSource.count) / (UIScreen.main.bounds.width / (barWidth + spaceBetweenBars))
chartSettings.zoomPan.minZoomX = zoomXValue
chartSettings.zoomPan.maxZoomX = zoomXValue

How can I show first value and last value in line Chart

I'm using charts library and i'm trying to add first value and last value on line chart graph.Please let me know how can I achieve it. I have tried customising drawValue method in linechartrenderer but didn't worked.
Here is my code
var months = ["Dec 15", "Jun 16", "Dec 16", "Jun 17", "Dec 17", "Jun 18"]
var unitsSold = [50.0, 25.0, 50.0, 75.0, 100.0, 75.0]
Viewdidload:
setChart(dataPoints: months, values: unitsSold)
Method:
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(x: Double(i), y: values[i], data: dataPoints[i] as AnyObject)
dataEntries.append(dataEntry)
}
let chartDataSet = LineChartDataSet(values: dataEntries, label: nil)
chartDataSet.setColor(UIColor(red: 53/255, green: 85/255, blue: 123/255, alpha: 1))
chartDataSet.circleRadius = 5
chartDataSet.circleHoleRadius = 2
chartDataSet.drawValuesEnabled = false
chartDataSet.drawCirclesEnabled = false
let chartData = LineChartData(dataSets: [chartDataSet])
defaultChartView.data = chartData
defaultChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: months)
defaultChartView.xAxis.labelPosition = .bottom
defaultChartView.xAxis.drawGridLinesEnabled = false
//lineChartView.xAxis.avoidFirstLastClippingEnabled = true
defaultChartView.xAxis.axisMinimum = 0
defaultChartView.xAxis.granularity = 1
defaultChartView.rightAxis.drawAxisLineEnabled = false
defaultChartView.rightAxis.drawLabelsEnabled = false
defaultChartView.rightAxis.enabled = false
defaultChartView.leftAxis.drawAxisLineEnabled = false
defaultChartView.leftAxis.axisMinimum = 0.0
defaultChartView.leftAxis.drawLabelsEnabled = false
//lineChartView.leftAxis.drawGridLinesEnabled = false
//lineChartView.leftAxis.granularityEnabled = false
defaultChartView.pinchZoomEnabled = true
defaultChartView.doubleTapToZoomEnabled = true
defaultChartView.legend.enabled = false
defaultChartView.chartDescription?.text = " "
}
viewDidLoad:
guard let firstMonth = months.first, let lastMonth = months.last else {
return
}
let myMonths = [firstMonth, lastMonth]
guard let firstValue = unitsSold.first, let lastValue = unitsSold.last else {
return
}
let myValues = [firstValue, lastValue]
setChart(dataPoints: myMonths, values: myValues)
Solution is go to linechartrenderer file and replace drawValues method
open override func drawValues(context: CGContext)
{
guard
let dataProvider = dataProvider,
let lineData = dataProvider.lineData
else { return }
if isDrawingValuesAllowed(dataProvider: dataProvider)
{
var dataSets = lineData.dataSets
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< dataSets.count
{
guard let dataSet = dataSets[i] as? ILineChartDataSet else { continue }
if !shouldDrawValues(forDataSet: dataSet)
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let iconsOffset = dataSet.iconsOffset
// make sure the values do not interfear with the circles
var valOffset = Int(dataSet.circleRadius * 1.75)
if !dataSet.isDrawCirclesEnabled
{
valOffset = valOffset / 2
}
_xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
for j in stride(from: _xBounds.min, through: min(_xBounds.min + _xBounds.range, _xBounds.max), by: 1)
{
guard let e = dataSet.entryForIndex(j) else { break }
if(j == 0 || j == dataSet.entryCount - 1)
{
pt.x = CGFloat(e.x)
pt.y = CGFloat(e.y * phaseY)
pt = pt.applying(valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
if dataSet.isDrawValuesEnabled {
ChartUtils.drawText(
context: context,
text: formatter.stringForValue(
e.y,
entry: e,
dataSetIndex: i,
viewPortHandler: viewPortHandler),
point: CGPoint(
x: pt.x,
y: pt.y - CGFloat(valOffset) - valueFont.lineHeight),
align: .center,
attributes: [NSAttributedStringKey.font: valueFont, NSAttributedStringKey.foregroundColor: dataSet.valueTextColorAt(j)])
}
if let icon = e.icon, dataSet.isDrawIconsEnabled
{
ChartUtils.drawImage(context: context,
image: icon,
x: pt.x + iconsOffset.x,
y: pt.y + iconsOffset.y,
size: icon.size)
}
}
else{
}
}
}
}
}
Set below property of X axis
barChartView.xAxis.setLabelCount(2, force: true)

Charts, HorizontalBarChartView, how set values alignment = Center?

Swift 3.1, Charts, Multiple cells in tableView with HorizontalBarChartView.
Is it possible to align the value - centered?
Setup charts data:.
func refreshData() {
guard let item = self.item, !item.tasks.isEmpty else {
return
}
self.titleName.text = item.name
self.leftNameMargin.constant = CGFloat(30 * item.level)
self.titleName.textColor = UIColor(hexString: item.color)
let font = UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightSemibold)
var colors: [UIColor] = []
var yValues: [Double] = []
var count = 0.0
for task in item.tasks {
count += Double(task.count)
yValues.append(Double(task.count))
colors.append(UIColor(hexString: task.valueColor))
}
let suffix = String(format: NSXLocalization.string(forKey: KEY_STR_PERCENT)) //fixes '%' duplication
let formatter = NumberFormatter()
formatter.roundingMode = .floor
formatter.numberStyle = .percent
formatter.positiveSuffix = suffix
formatter.negativeSuffix = suffix
formatter.zeroSymbol = ""
let dataEntry = BarChartDataEntry(x: 0.0, yValues: yValues.map { ($0 / count) })
let dataSet = BarChartDataSet(values: [dataEntry], label: nil)
dataSet.colors = colors
dataSet.valueTextColor = .white
dataSet.barBorderColor = .black
dataSet.barBorderWidth = 1.0
dataSet.drawValuesEnabled = true
dataSet.valueFormatter = DefaultValueFormatter(formatter: formatter)
let data = BarChartData(dataSets: [dataSet])
data.setValueFont(font)
data.setDrawValues(true)
data.highlightEnabled = true
self.chart.data = data
}
I Reviewed all internal methods in the charts, but never found a way to center the y values.

Why is my screen not rendering anything?

I have the following code. When I run this I am getting a blank screen. This block of code is inside sceneDidLoad() so they will get executed but not displaying anything. Am I missing something ?
let worldNode = SKNode()
let height = 100
let width = 100
let regions:[Float: String] = [-0.04: "sand", -0.08: "water", 0.9: "grass"]
let noiseSource = GKPerlinNoiseSource()
let noise: GKNoise = GKNoise(noiseSource: noiseSource)
let noiseMap: GKNoiseMap = GKNoiseMap(noise: noise)
let tileMapNode = SKTileMapNode()
tileMapNode.enableAutomapping = true
tileMapNode.numberOfRows = height
tileMapNode.numberOfColumns = width
worldNode.addChild(tileMapNode)
for y in 0 ... height {
for x in 0 ... width {
let currentHeight = noiseMap.value(atPosition: vector2(Int32(x), Int32(y)));
for (key, value) in regions {
if (currentHeight <= key) {
//colourMap [y * mapChunkSize + x] = regions[i];
let tileSize = CGSize(width: 32.0, height: 32.0)
let tileTexture = SKTexture(imageNamed: value)
let tileDef = SKTileDefinition(texture: tileTexture, size: tileSize)
let tileGroup = SKTileGroup(tileDefinition: tileDef)
tileMapNode.setTileGroup(tileGroup, forColumn: x, row: y)
print("Tiling: \(value)")
break;
}
}
}
}
self.addChild(worldNode)

instaFilter Processor error - missing return in a function expected to return

I'm currently learning swift and I'm currently taking a class for it. We are told to write a code to apply filters to a sample picture to change a given intensity of a color on an image in its parameter and then return the modified image.
In the code that I have written, on the last couple lines, it states an error saying
missing return in a function expected to return 'UIImage'
my class code:
import UIKit
let image = UIImage(named: "sample")!
class brightnessFilter {
func increaseContrast(image: UIImage) -> UIImage{
var rgbaImage = RGBAImage(image: image)!
let avgRed = 118
let avgGreen = 98
let avgBlue = 83
for y in 0..<rgbaImage.height {
for x in 0..<rgbaImage.width {
let index = y * rgbaImage.width + x
var pixel = rgbaImage.pixels[index]
let redLum = Int(pixel.red) - avgRed
let greenLum = Int(pixel.green) - avgGreen
let blueLum = Int(pixel.blue) - avgBlue
pixel.red = UInt8(max(min(255, avgRed + 2 * redLum), 0))
pixel.blue = UInt8(max(min(255, avgBlue + 2 * blueLum), 0))
pixel.green = UInt8(max(min(255, avgGreen + 2 * greenLum), 0))
rgbaImage.pixels[index] = pixel
}
}
let newImage1 = rgbaImage.toUIImage()!
return (newImage1)
}
}
let test = brightnessFilter()
let processedImg = test.increaseContrast(image)
class redFilter {
func increaseContrast(image: UIImage) -> UIImage{
var rgbaImage = RGBAImage(image: image)!
let avgRed = 118
for y in 0..<rgbaImage.height {
for x in 0..<rgbaImage.width {
let index = y * rgbaImage.width + x
var pixel = rgbaImage.pixels[index]
let redDiff = Int(pixel.red) - avgRed
if (redDiff > 0) {
pixel.red = UInt8( max(0, min(255, avgRed + redDiff * 5)))
rgbaImage.pixels[index] = pixel
}
}
let newImage2 = rgbaImage.toUIImage()!
return (newImage2)
}
}
}
let test2 = redFilter()
RGBA class:
import UIKit
public struct Pixel {
public var value: UInt32
public var red: UInt8 {
get {
return UInt8(value & 0xFF)
}
set {
value = UInt32(newValue) | (value & 0xFFFFFF00)
}
}
public var green: UInt8 {
get {
return UInt8((value >> 8) & 0xFF)
}
set {
value = (UInt32(newValue) << 8) | (value & 0xFFFF00FF)
}
}
public var blue: UInt8 {
get {
return UInt8((value >> 16) & 0xFF)
}
set {
value = (UInt32(newValue) << 16) | (value & 0xFF00FFFF)
}
}
public var alpha: UInt8 {
get {
return UInt8((value >> 24) & 0xFF)
}
set {
value = (UInt32(newValue) << 24) | (value & 0x00FFFFFF)
}
}
}
When a method declaration is written with return value, you must make sure it is always return a value.
I believe your error is in the following method:
func increaseContrast(image: UIImage) -> UIImage {
var rgbaImage = RGBAImage(image: image)!
let avgRed = 118
let newImage2 = UIImage() //<-- Added
for y in 0..<rgbaImage.height {
for x in 0..<rgbaImage.width {
let index = y * rgbaImage.width + x
var pixel = rgbaImage.pixels[index]
let redDiff = Int(pixel.red) - avgRed
if (redDiff > 0) {
pixel.red = UInt8( max(0, min(255, avgRed + redDiff * 5)))
rgbaImage.pixels[index] = pixel
}
}
let newImage2 = rgbaImage.toUIImage()!
return (newImage2) //<---NOTICE
}// <---FIX
}
Notice: that the return statement is in the for loop, meaning the method might not always return a value.
Fix: Put the return statement under the curly brackets marked in the code.
Added: You must return a value, therefore, you must create one
Side note: Make sure to handle nil

Resources