Are pointers to Objective-C arrays (via a bridging header) allowed? - ios

I have been trying to get the GLCameraRipple sample from Apple running in a swift project. Unfortunately this relies heavily on using C style, thread-safe arrays only available in Objective-C.
I have been trying to use a bridging header so that the simulation can run in Objective-C code, and the drawing can run in swift code. That way the thread-safe thing would not be an issue.
I have taken the Objective-C code and translated it almost completely into swift with a few exceptions. I did cull some of the extra math since the texture is the same size as the screen for my needs. If you want to check my translation I have put them below.
Anyway I have made a class that will run in any xcode project with an opengl environment.
import Foundation
import GLKit
import OpenGLES
class WaterDrawer
{
static var sim = RippleModel()
static var shade = Shader("Shader2")
static func pt(pt: CGPoint)
{
sim.initiateRippleAtLocation(pt)
}
static func firstStart(width: Int, height: Int)
{
sim.initWithScreenWidth(width / 4, iheight: height / 4, accWidth: width, accHeight: height)
shade.begin()
buildMatrix(width, height: height)
bufferSetup()
}
static func draw()
{
glUseProgram(shade.progId)
let posLoc = GLuint(glGetAttribLocation(shade.progId, "pos"))
let texLoc = GLuint(glGetAttribLocation(shade.progId, "tc"))
glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));
glVertexAttribPointer(texLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
glEnableVertexAttribArray(texLoc)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO)
glVertexAttribPointer(posLoc, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), 0, BUFFER_OFFSET(0))
glEnableVertexAttribArray(posLoc)
let uniOrtho = glGetUniformLocation(shade.progId, "matrix")
glUniformMatrix4fv(uniOrtho, 1, GLboolean(GL_FALSE), &orthographicMatrix)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO)
glDrawElements(GLenum(GL_TRIANGLE_STRIP), GLsizei(sim.getIndexCount()), GLenum(GL_UNSIGNED_SHORT), nil)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
glDisableVertexAttribArray(posLoc)
glDisableVertexAttribArray(texLoc)
}
static func update()
{
sim.runSimulation()
}
static var posVBO:GLuint = 0
static var texVBO:GLuint = 0
static var indVBO:GLuint = 0
static func bufferSetup()
{
Whirl.crashLog("Started passing in buffer data")
glGenBuffers(1, &indVBO);
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indVBO);
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), GLsizeiptr(sim.getIndexSize()), sim.getIndices(), GLenum(GL_STATIC_DRAW));
glGenBuffers(1, &posVBO);
glBindBuffer(GLenum(GL_ARRAY_BUFFER), posVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getVertices(), GLenum(GL_STATIC_DRAW));
glGenBuffers(1, &texVBO);
glBindBuffer(GLenum(GL_ARRAY_BUFFER), texVBO);
glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sim.getVertexSize()), sim.getTexCoords(), GLenum(GL_DYNAMIC_DRAW));
Whirl.crashLog("Finished passing in buffer Data")
}
static var orthographicMatrix:[GLfloat] = []
static func buildMatrix(width: Int, height: Int)
{
orthographicMatrix = glkitmatrixtoarray(GLKMatrix4MakeOrtho(0, GLfloat(width), 0, GLfloat(height), -100, 100))
//Storage.upScaleFactor
}
static func glkitmatrixtoarray(mat: GLKMatrix4) -> [GLfloat]
{
var buildme:[GLfloat] = []
buildme.append(mat.m.0)
buildme.append(mat.m.1)
buildme.append(mat.m.2)
buildme.append(mat.m.3)
buildme.append(mat.m.4)
buildme.append(mat.m.5)
buildme.append(mat.m.6)
buildme.append(mat.m.7)
buildme.append(mat.m.8)
buildme.append(mat.m.9)
buildme.append(mat.m.10)
buildme.append(mat.m.11)
buildme.append(mat.m.12)
buildme.append(mat.m.13)
buildme.append(mat.m.14)
buildme.append(mat.m.15)
return buildme
}
}
So theoretically this code can use either the swift implementation or the Objective-C implementation, I just need to switch the way the mesh is initiated.
Trouble is when I use the Objective-C one the screen is blank, I have checked, and the buffer data looks really weird in the frame capture.
Are you allowed to pass in data from an Objective-C code to a glBuffer?
Simulation.swift
import Foundation
import GLKit
import OpenGLES
class RippleModel
{
var screenWidth:UInt32 = 0
var screenHeight:UInt32 = 0
var poolWidth:UInt32 = 0
var poolHeight:UInt32 = 0
var screenWidthi:Int = 0
var screenHeighti:Int = 0
var poolWidthi:Int = 0
var poolHeighti:Int = 0
let touchRadius:Int = 5 //5 i think
var rippleVertices:[GLfloat] = []
var rippleTexCoords:[GLfloat] = []
var rippleIndices:[GLushort] = []//NOTE IF CHANGE THIS TO INTO SO MUCH DRAW CALL
var rippleSource:[GLfloat] = []
var rippleDest:[GLfloat] = []
var rippleCoeff:[GLfloat] = []
var VertexSize:GLsizeiptr = 0
var IndicieSize:GLsizeiptr = 0
var IndicieCount:Int = 0
func calculateSizes()
{
VertexSize = rippleVertices.count * sizeof(GLfloat)
IndicieSize = rippleIndices.count * sizeof(GLushort)
IndicieCount = rippleIndices.count
Whirl.crashLog("Data sizes Vertex size \(VertexSize)\tIndicie Size \(IndicieSize) \tIndicie Count \(IndicieCount)")
}
func figureOutCoefficent()
{
for y in 0...(2 * touchRadius)
{
for x in 0...(2 * touchRadius)
{
let dx = x - touchRadius
let dy = y - touchRadius
let distance = sqrt(GLfloat(dx * dx + dy * dy))
let me = y * (touchRadius*2 + 1) + x
if (distance <= GLfloat(touchRadius))
{
let factor = distance / GLfloat(touchRadius)
rippleCoeff[me] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
}
else
{
rippleCoeff[me] = 0.0
}
}
}
}
init()
{
}
func initWithScreenWidth( iwidth: Int, iheight: Int, accWidth: Int, accHeight: Int)
{
screenWidth = UInt32(accWidth);screenWidthi = Int(screenWidth)
screenHeight = UInt32(accHeight);screenHeighti = Int(screenHeight)
poolWidth = UInt32(iwidth);poolWidthi = Int(poolWidth)
poolHeight = UInt32(iheight);poolHeighti = Int(poolHeight)
//WE DONT NEED TEX COORD MUMBO JUMBO IT IS FULL SCREEN ALREADY
Whirl.crashLog("Started allocation")
rippleCoeff = [GLfloat](count: Int( (touchRadius * 2 + 1) * (touchRadius*2 + 1) ), repeatedValue: 0)
figureOutCoefficent()
let simCount:Int = Int(poolWidth + 2) * Int(poolHeight + 2)
rippleSource = [GLfloat](count: simCount, repeatedValue: 0)
rippleDest = [GLfloat](count: simCount, repeatedValue: 0)
let locb:Int = Int(poolWidth * poolHeight * 2)
rippleVertices = [GLfloat](count: locb, repeatedValue: 0)
rippleTexCoords = [GLfloat](count: locb, repeatedValue: 0)
rippleIndices = [GLushort](count: Int(poolHeight - 1) * Int((poolWidth * 2) + 2), repeatedValue: 0)
Whirl.crashLog("Finished allocation")
initMesh()
calculateSizes()
}
func initMesh()
{
Whirl.crashLog("Started initting pos coords")
for i in 0..<poolHeight
{let ii = GLfloat(i)
for j in 0..<poolWidth
{let jj = GLfloat(j)
let cordb:Int = Int(i*poolWidth+j)*2
rippleVertices[cordb + 0] = (jj / GLfloat(poolWidth - 1)) * GLfloat(screenWidth)
rippleVertices[cordb + 1] = (ii / GLfloat(poolHeight - 1)) * GLfloat(screenHeight)
rippleTexCoords[cordb + 0] = ii / GLfloat(poolHeight - 1)
rippleTexCoords[cordb + 1] = (jj/GLfloat(poolWidth - 1))
}
}
Whirl.crashLog("Finished initting pos coords")
Whirl.crashLog("Started initting index coords")
var index = 0
for i in 0 ..< poolHeighti-1
{
for j in 0 ..< poolWidthi
{
if (i%2 == 0)
{
// emit extra index to create degenerate triangle
if (j == 0)
{
rippleIndices[index] = GLushort(i*poolWidthi+j);
index += 1;
}
rippleIndices[index] = GLushort(i*poolWidthi+j);
index += 1;
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
// emit extra index to create degenerate triangle
if (j == (poolWidthi-1))
{
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
}
}
else
{
// emit extra index to create degenerate triangle
if (j == 0)
{
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
}
rippleIndices[index] = GLushort((i+1)*poolWidthi+j);
index += 1;
rippleIndices[index] = GLushort(i * poolWidthi + j);
index += 1;
// emit extra index to create degenerate triangle
if (j == (poolWidthi-1))
{
rippleIndices[index] = GLushort(i * poolWidthi + j);
index += 1;
}
}
}
}
Whirl.crashLog("Finished initting coords")
}
var firstUpdate = true
func runSimulation()
{
if (firstUpdate)
{firstUpdate = false; Whirl.crashLog("First update")}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//dispatch_apply(Int(poolHeight), queue, {(y: size_t) -> Void in
for y in 0..<poolHeighti {
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let me:Int = (y + 1) * (pw + 2) + x + 1
let a = self.rippleSource[ai]
let b = self.rippleSource[bi]
let c = self.rippleSource[ci]
let d = self.rippleSource[di]
var result = (a + b + c + d) / 2.0 - self.rippleDest[me]
result -= result / 32.0
self.rippleDest[me] = result
}
}
//)
let hm1 = GLfloat(poolHeight - 1)
let wm1 = GLfloat(poolWidth - 1)
//dispatch_apply(poolHeighti, queue, {(y: size_t) -> Void in
for y in 0..<poolHeighti{
let yy = GLfloat(y)
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{let xx = GLfloat(x)
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let a = self.rippleDest[ai]
let b = self.rippleDest[bi]
let c = self.rippleDest[ci]
let d = self.rippleDest[di]
var s_offset = ((b - a) / 2048)
var t_offset = ((c - d) / 2048)
s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
s_offset = (s_offset > 0.5) ? 0.5 : s_offset;
t_offset = (t_offset > 0.5) ? 0.5 : t_offset;
let s_tc = yy / hm1
let t_tc = xx / wm1
let me = (y * pw + x) * 2
self.rippleTexCoords[me + 0] = s_tc + s_offset
self.rippleTexCoords[me + 1] = t_tc + t_offset
}
}
//)
let pTmp = rippleDest
rippleDest = rippleSource
rippleSource = pTmp
}
var firstRipple:Bool = true
func initiateRippleAtLocation(location: CGPoint)
{
if (firstRipple)
{firstRipple = false; Whirl.crashLog("First ripple placement")}
let xIndex = Int((GLfloat(location.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex = Int((1.0 - (GLfloat(location.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let lowy = yIndex - touchRadius
let highy = yIndex + touchRadius
let lowx = xIndex - touchRadius
let highx = xIndex + touchRadius
//Whirl.crashLog("Ripple at (\(xIndex) , \(yIndex))\tX:(\(lowx) - \(highx))\tY:(\(lowy) - \(highy))")
for y in lowy...highy
{
for x in lowx...highx
{
if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
{
let ind = (poolWidthi + 2) * (y + 1) + x + 1
let coef = (y-(yIndex-touchRadius))*(touchRadius*2+1)+x-(xIndex-touchRadius)
let past = rippleSource[ind]
let coe = rippleCoeff[coef]
if (coe < past)
{
rippleSource[ind] = coe
}
}
}
}
}
func rippleLine(location1: CGPoint, location2: CGPoint)
{
if (firstRipple)
{firstRipple = false; Whirl.crashLog("First ripple placement")}
let xIndex1 = Int((GLfloat(location1.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex1 = Int((1.0 - (GLfloat(location1.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let xIndex2 = Int((GLfloat(location2.x) / GLfloat(screenWidth)) * GLfloat(poolWidthi))
let yIndex2 = Int((1.0 - (GLfloat(location2.y) / GLfloat(screenHeighti))) * GLfloat(poolHeight))
let lowy1 = yIndex1 - touchRadius
let highy1 = yIndex1 + touchRadius
let lowx1 = xIndex1 - touchRadius
let highx1 = xIndex1 + touchRadius
let lowy2 = yIndex2 - touchRadius
let highy2 = yIndex2 + touchRadius
let lowx2 = xIndex2 - touchRadius
let highx2 = xIndex2 + touchRadius
let lowx = min(lowx1, lowx2)
let highx = max(highx1, highx2)
let lowy = min(lowy1, lowy2)
let highy = max(highy1, highy2)
for y in lowy...highy
{
for x in lowx...highx
{
if (x > 0 && x < (poolWidthi - 1) && y > 0 && y < poolHeighti)
{
let ind = (poolWidthi + 2) * (y + 1) + x + 1
let tar = ldist(CGPoint(x: xIndex1, y: yIndex1), p2: CGPoint(x: xIndex2, y: yIndex2), me: CGPoint(x: x, y: y))
let dx = x - Int(tar.x)
let dy = y - Int(tar.y)
let distq = (dx * dx + dy * dy)
if (distq < touchRadius * touchRadius)
{
let factor = sqrt(GLfloat(distq)) / GLfloat(touchRadius)
rippleSource[ind] = -(cos(factor*GLfloat(M_PI))+1.0) * 256.0;
}
//rippleSource[ind] = 1000
}
}
}
}
func ldist(p1: CGPoint, p2: CGPoint, me: CGPoint) -> CGPoint
{
let diffX = p2.x - p1.x
let diffY = p2.y - p1.y
var target = CGPoint()
if ((diffX == 0) && (diffY == 0))
{
target = p1
}
let t = ((me.x - p1.x) * diffX + (me.y - p1.y) * diffY) / (diffX * diffX + diffY * diffY)
if (t < 0)
{
target = p1
}
else if (t > 1)
{
target = p2
}
else
{
target = CGPoint(x: (p1.x + t * diffX), y: (p1.y + t * diffY))
}
let int = CGPoint(x: round(target.x), y: round(target.y))
return int
}
func getVertices() -> [GLfloat]
{
//Return the mesh positions
return rippleVertices
}
func getTexCoords() -> [GLfloat]
{
//Return the array of texture coords
return rippleTexCoords
}
func getIndices() -> [GLushort]
{
//Return the array of indices
return rippleIndices
}
func getVertexSize() -> GLsizeiptr
{
//Return the size of the mesh position array
return VertexSize
}
func getIndexSize() -> GLsizeiptr
{
//Return the byte size of the incicie array
return IndicieSize
}
func getIndexCount() -> GLsizeiptr
{
//This goes in the draw call, count of indices
return IndicieCount
}
}
RippleModel.m (from apple)

Are you allowed to pass in data from an objective-c code to a glBuffer?
Why wouldn't you be allowed? Swift has a pointer API (UnsafePointer<T>, UnsafeMutablePointer<T>, etc.) exactly for this purpose. Obviously this is "unsafe" in the sense that the underlying memory the [Objective-]C pointer points to could change at anytime without the Swift pointer knowing. It also has no information about the size of the memory block that it points to.
Any C pointers or arrays can be bridged to Swift (probably as UnsafeMutablePointer<Void> which you will need to cast to your OpenGL type).
You can avoid any risk of referencing invalid memory by dereferencing the pointer (if it is non-nil) and copying the value stored at the pointer to a variable in your Swift application.

With OpenGL ES being a pure set of C functions, I don't think passing a pointer of swift datatypes will work easily.
The following code will give you a hint of how to pass the index buffer.
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
var indexBuffer: GLuint = GLuint()
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))
Reference: Here is a link with a working code. https://github.com/bradley/iOSSwiftOpenGL/blob/master/iOSSwiftOpenGL/OpenGLView.swift

Related

How tom Show 3D pie-chart in swift 4 in my app

I am trying to show a 3D pie-chart in my app in swift 4.
but can't find any solution.does anyone help me or give me any suggestion please??
private func createPieChart() -> SCNNode {
let aNode = SCNNode()
var total:Float = 0.0
//let numRows = data.numberOfRows()
let numColumns = data.numberOfColums()
let i = 0
for j in 0 ..< numColumns {
let val = data.valueForIndexPath(row:i, column: j)
total = total + val
}
var startDeg:Float = 0.0
var startRad:Float = 0.0
for j in 0 ..< numColumns {
let val = data.valueForIndexPath(row:i, column: j)
let pct = val*360.0/total
startRad = Float(startDeg) * Float(M_PI) / Float(180.0)
let endDeg = startDeg + pct - 1.0
let endRad:Float = Float(endDeg) * Float(M_PI) / Float(180.0)
let circlePath = UIBezierPath()
circlePath.move(to: CGPoint.zero)
circlePath.addArc(withCenter: CGPoint.zero, radius: 20.0, startAngle:CGFloat(startRad), endAngle: CGFloat(endRad), clockwise: true)
startDeg = endDeg + 1
let node = SCNNode(geometry: SCNShape(path:circlePath, extrusionDepth: 5.0))
node.geometry?.firstMaterial?.diffuse.contents = data.colorForIndexPath(row: i, column: j)
aNode.addChildNode(node)
}
return aNode
}

Different results and codes for the discrete cosine transform... what is going on?

I need to do a Discreet Cosine Transform of the following data:
0.6191342,0.6197224,0.61898607,0.61912596,0.6190106,0.61988443,0.61900085,0.6187835,0.6180295,0.61910814,0.6146555,0.6182434,0.6189235,0.61222005,0.6207976,0.6218684,0.62007576,0.6216523,0.6215335,0.62065303,0.6205161,0.61968786,0.619246,0.6213837,0.62122154,0.6192542,0.61824924,0.61987126,0.62156975,0.62128264,0.6205598,0.62057704,0.62053716,0.62275934,0.6218448,0.6203091,0.6178272,0.6140544,0.6213627,0.62143743,0.6132956,0.61910033,0.61519396,0.62216187,0.6215059,0.6197418,0.615724,0.62262917,0.62247676,0.62028235,0.6186407,0.619341,0.6152448,0.62161505,0.61356294,0.6133514,0.618384,0.6184519,0.6158993,0.6210517,0.61071134,0.62111616,0.61093444,0.62230366,0.6216592,0.61184555,0.61515874,0.6136047,0.6233515,0.618276,0.6159197,0.61444646,0.6185363,0.6162487,0.61572075,0.6194457,0.61314666,0.61829245,0.62141377,0.62105316,0.6124673,0.6179071,0.6186554,0.62159,0.61449164,0.61788505,0.6064126,0.6184563,0.6143939,0.6169126,0.61230534,0.6193385,0.6139966,0.6149371,0.6178339,0.61179554,0.6135024,0.61419034,0.614619,0.6137465,0.6185665,0.6185372,0.6163691,0.6195464,0.6170328,0.61263216,0.6161196,0.6184589,0.622137,0.61809236,0.61836344,0.61896133,0.6169496,0.6195432,0.6197563,0.61895114,0.61758405,0.61847824,0.61592484,0.6179055,0.61649424,0.61602193,0.6174835,0.61842364,0.60891753,0.61700743,0.6159329,0.61829287,0.6166717,0.6159072,0.6157982,0.6081088,0.6191729,0.61839896,0.615376,0.6154309,0.6119571,0.61734617,0.6171004,0.6178271,0.6169227,0.6172922,0.61745894,0.6195544,0.6103485,0.6142039,0.6166354,0.61975944,0.6184104,0.6177316,0.6150697,0.61001426,0.6108277,0.617212,0.6106007,0.61446583,0.61284953,0.6152104,0.6181612,0.61701053,0.6148785,0.61547005,0.62181646,0.618621,0.6161165,0.616407,0.6115453,0.6172732,0.61757433,0.61611485,0.61767805,0.61765575,0.61649793,0.6184486,0.6195102,0.61967367,0.6210996,0.61727804,0.6189702,0.6188129,0.6160338,0.6205609,0.6199804,0.6170756,0.6182058,0.61902076,0.62221605,0.6212938,0.61759907,0.6170265,0.6073142,0.6191233,0.61933994,0.61591357,0.6168009,0.6149173,0.6155775,0.6203353,0.6168877,0.61844844,0.60965574,0.61050487,0.62154305,0.62103915,0.6164665,0.6161686,0.60936993,0.614351,0.6204919,0.61622816,0.61612433,0.61211497,0.61347705,0.6192275,0.6165203,0.6156739,0.61536443,0.6136969,0.6195982,0.6201504,0.61684716,0.6125972,0.61233103,0.6179449,0.6163167,0.6089562,0.60863984,0.61114866,0.6104453,0.6166812,0.61086583,0.6118273,0.6211713,0.6160922,0.60824126,0.60837793,0.61538464,0.6222241,0.60950315,0.61592793,0.60851187,0.613283,0.61787575,0.6204593,0.6155273,0.6085147,0.6164997,0.61334276,0.61671215,0.6086348,0.6089769,0.61735654,0.6203436,0.60964227,0.6184011,0.6144072
If I use the Accelerate functions provided by Apple, I get these results:
2.669825,0.23372388,0.034602005,0.14609262,-0.05658116,0.028039198,-0.019894773,-0.12209733,0.022227166,0.0051003816,-0.042596065,-0.04589792,0.01035949,-0.019523097,0.077776365,0.0030713473,-0.078441024,-0.00070093106,0.01997262,0.06481835,-0.004874494,0.023854036,0.029294237,0.011619994,-0.0012118752,0.010400612,0.023407647,-0.05563956,0.038198948,-0.01233741,0.009424317,0.039608873,0.05801,0.028565174,-0.012889689,0.021731874,-0.026493106,-0.048108768,0.0045189788,-0.032068893,-0.017894993,-0.025662154,0.010751593,-0.07121442,0.06277961,0.0022988198,-0.018414639,-0.021932043,-0.020916257,-0.01747331,0.006716689,0.023302665,0.0068657864,-0.019596279,-0.043121584,0.04483221,-0.00012186449,-0.012160094,0.011104634,-0.015813472,0.023498433,0.02872037,0.014691476,0.015423553,-0.032783255,0.028947365,0.03251956,-0.016012289,-0.018248938,0.026564144,-0.034706548,0.012790314,0.002194486,0.04613065,-0.05747463,0.010088965,0.017059956,-0.04142371,-0.040067486,0.0029621175,0.07121314,-0.0064264582,-0.0064690933,-0.040944442,-0.0025974065,0.0075896196,-0.006084161,-0.027271878,0.056449506,-0.01756429,0.020225035,0.05740238,-0.07323427,0.091452986,-0.06606907,-0.00599443,0.03895919,0.0029399507,0.0050259903,-0.017262679,-0.052305933,0.0132182,-0.14926372,0.12026562,0.06996072,0.050748315,0.020096999,-0.017148953,0.006768549,-0.07308701,0.045742266,-0.055744015,0.034470245,-0.06591675,0.012785097,-0.045998022,0.028786233,-0.0006729504,0.026651034,0.016280383,-0.016419016,-0.0235405,-0.011106867,0.0060093636,-0.026253335,-0.020966358,0.049879722,-0.019093664,0.055243053,0.008216016,0.039922368,-0.05096092,0.010148679,-0.011200655,0.044212196,-0.012730424,0.027963173,-0.0050371652,0.0006729523,-0.02703674,-0.040479846,0.0032800399,0.019346198,0.03412081,-0.0062747486,-0.018566221,-0.011666842,0.02345107,-0.07089561,0.023972765,-0.0076217707,0.00794466,-0.008454496,-0.051500462,0.007845432,-0.046568125,-0.018137766,0.026703745,0.035737798,-0.061839998,-0.00884305,0.009104564,0.052314416,0.028979728,-0.017012393,-0.019422699,-0.049617197,0.03505949,0.005899897,0.031378012,0.02203784,0.05013973,-0.014152746,0.029270608,0.049914937,0.01226829,-0.038096413,0.012367716,-0.04856258,0.008609608,-0.014275378,-0.00032820972,0.003259441,0.04173329,0.0026449636,0.020232702,-0.058400147,0.006697319,-0.083465755,0.023861019,-0.019418886,-0.034204446,0.057170536,-0.03352673,-0.020436082,-0.024796713,-0.054371275,0.055950172,-0.01681035,0.018895034,0.042727623,0.040553555,-0.049501,0.003925497,-0.034148764,-0.00027683005,-0.054910377,0.03833572,0.053599093,0.02369698,-0.0021882567,0.04318303,0.0055106683,-0.026357781,-0.0022721058,-0.036762282,0.06495822,0.030521873,0.003908515,-0.052683424,-0.00785333,-0.0245375,-0.006546188,0.03067175,0.046067707,0.0047659995,-0.03191337,0.010508363,-0.0308632,-0.016877536,-0.05901345,0.0061260397,0.008024132,0.052667245,-0.026830386,0.021430418,-0.044398945,-0.02600174,-0.032572,0.06329122,0.032917332,0.0284806,-0.074899085,-0.025770163,-0.015752867,0.0030335134,0.04120659,0.0026583495,-0.005403653,0.009906204,0.029109228,0.015893774,0.0023716427,-0.02794688,-0.033177476,-0.08380169
If I use a code I call dctA I get this:
0.16686402,-0.235977,0.23596367,-0.23594144,0.23591036,-0.23587029,0.23582156,-0.23576365,0.23569722,-0.23562174,0.23553737,-0.2354442,0.23534207,-0.2352311,0.2351113,-0.23498271,0.23484512,-0.23469894,0.23454358,-0.2343797,0.2342069,-0.23402523,0.23383485,-0.23363559,0.2334273,-0.23321046,0.2329848,-0.23275039,0.23250724,-0.23225537,0.23199482,-0.2317253,0.23144716,-0.23116058,0.23086505,-0.23056087,0.23024791,-0.22992653,0.22959618,-0.22925732,0.22890992,-0.22855341,0.22818917,-0.22781523,0.22743407,-0.22704314,0.22664468,-0.22623657,0.22582,-0.225396,0.22496259,-0.22452155,0.22407113,-0.22361335,0.22314598,-0.22267129,0.22218716,-0.22169586,0.2211951,-0.22068696,0.22016953,-0.21964486,0.21911088,-0.21856976,0.21801907,-0.21746023,0.21689478,-0.21631947,0.21573758,-0.21514617,0.2145479,-0.2139403,0.2133261,-0.21270223,0.212072,-0.21143214,0.2107861,-0.21013027,0.20946832,-0.20879678,0.20811911,-0.20743181,0.20673671,-0.2060339,0.2053268,-0.20460844,0.20388247,-0.20314853,0.20241094,-0.20166187,0.20090508,-0.20014101,0.19937299,-0.19859369,0.19780688,-0.19701274,0.19621103,-0.19540597,0.19458961,-0.19376592,0.19293484,-0.19210072,0.19125515,-0.19040233,0.18954237,-0.18867959,0.18780532,-0.18692416,0.18603577,-0.1851449,0.18424252,-0.1833334,0.18241717,-0.1814941,0.18056883,-0.17963219,0.17868869,-0.1777385,0.17678645,-0.17582284,0.17485264,-0.17387584,0.1728974,-0.17190763,0.17091122,-0.1699084,0.16890429,-0.16788879,0.16686694,-0.16583884,0.16480431,-0.16376887,0.16272213,-0.16166915,0.16061012,-0.15955035,0.15847927,-0.15740223,0.15631929,-0.15523578,0.15414095,-0.15304045,0.15193413,-0.15082765,0.14970991,-0.14858656,0.1474576,-0.14632308,0.14518869,-0.14404319,0.14289224,-0.14173594,0.14057998,-0.13941304,0.13824077,-0.13706335,0.13588662,-0.1346989,0.13350609,-0.13230827,0.13111141,-0.12990372,0.12869103,-0.12747958,0.12625119,-0.1250302,0.12379233,-0.122562,0.121327065,-0.120075285,0.118831374,-0.11758294,0.11631756,-0.11506039,0.11378633,-0.112520546,0.11125048,-0.10996368,0.10868541,-0.10739021,0.10610382,-0.104813375,0.10350613,-0.102208,0.100905985,-0.09958719,0.098277606,-0.096951276,0.09563441,-0.09431398,0.092976734,-0.09164931,0.090305135,-0.088970825,0.087633155,-0.086278856,0.08493474,-0.08358737,0.08222347,-0.0808699,0.079499744,-0.07814017,0.07677769,-0.07539867,0.07403045,-0.07265948,0.07127206,-0.069895685,0.0685029,-0.06712131,0.06573725,-0.06433683,0.062947854,-0.061542634,0.06014901,-0.05875311,0.057341076,-0.055940807,0.054538473,-0.053120058,0.05171367,-0.05029129,0.048881073,-0.047469016,0.046041086,-0.044625536,0.043194164,-0.041775327,0.0403549,-0.038918786,0.0374954,-0.03607061,0.03463024,-0.033202793,0.031759836,-0.030329958,0.028898928,-0.027452547,0.026019417,-0.024585323,0.02313597,-0.021700067,0.020249018,-0.018811548,0.017373376,-0.015920186,0.014480768,-0.013026423,0.0115859695,-0.0101450775,0.00868942,-0.0072478293,0.0058059655,-0.0043494827,0.0029072375,-0.0014504795
and if I use another code I have found on the web, that I call dctB I get this:
0.23598135,0.0065520015,-0.0014035295,-0.0014900116,-0.0029997544,-0.0022787564,0.003723558,-0.003108655,-0.0012933733,-0.0007105355,0.0012699091,-0.00060556503,0.0053185527,0.00076327357,-0.0011331664,0.005722867,0.0034567474,-0.0011424342,-0.0013203556,0.0021249577,-0.0029971765,0.0006293817,0.0019937858,0.0026412704,0.00016487329,-0.003959481,0.00039281833,-0.0024429162,0.00060916966,-0.0019161169,-0.006625204,-0.002263753,0.00040166255,-0.0013965253,-0.00019885821,-0.010229679,0.0015206567,-0.0053624627,0.00058637373,0.0070882766,-0.0044516595,0.0010087036,-0.0064169616,0.0043392666,0.0012746729,0.0014619434,-0.0050648195,0.0009482073,0.004468296,-0.0015502489,-0.0043041282,-0.001236145,0.0048462045,-0.003547573,0.0035744759,0.0021012123,0.0039755865,0.0017270996,-0.0047634826,0.0021218802,0.003715937,-0.0038134162,-0.0031784503,0.0021606751,0.0063801087,-6.5251596e-05,-0.004479158,-0.0052841934,0.0056381524,0.0003858073,-0.00277002,0.001508747,0.005996452,-0.0019169269,0.001555898,0.00014130188,0.005808804,0.0037767508,-0.0026520337,-0.0018158474,0.0033173792,0.0046277773,-0.0006036768,-0.0019087599,9.9361154e-05,0.004506388,-0.0044565895,0.00051484356,-0.0026925507,0.005224032,8.564865e-05,-0.0057873107,-0.000118939184,-0.0065063527,0.004078492,0.0003850522,-0.0038591337,0.0016885462,-0.0028994652,0.00063551,0.0018036738,-0.0020673752,-1.50109045e-05,0.0007685168,-0.0028343478,0.003231319,0.0062061716,0.0032275403,-0.002344687,0.000663079,-0.0016223937,-0.0045130113,0.0058470825,0.00283345,-0.0020404255,-9.103818e-05,0.004184909,-0.003951648,-0.00038761974,0.0010700208,-0.0066716103,-0.00018829755,0.0036042533,-0.0043730726,-0.002380092,0.0013307306,-0.0021570993,0.007163353,0.16732568,0.0021171984,0.00011411852,-0.00347561,-0.0018730971,0.0011592627,0.0017720436,-0.0042686476,0.004867761,-0.002120747,0.002259214,0.003109498,0.0034014524,0.0012342912,0.00042545033,0.005238078,-0.0009351839,0.0028766692,-0.0002561589,0.0023975722,-0.0019213242,-0.0023478842,-0.0033766865,0.0005857277,0.0030684788,-0.006383024,0.00048669687,-0.0014512719,-0.0009451752,-0.0033242197,-0.006483069,-0.004888436,0.00435442,-0.0022291946,-0.0043107485,-0.007959526,0.0022944517,-0.0017021666,0.000734793,0.0049511404,-0.003661971,0.00094925304,-0.004634777,0.0016841891,0.0016499859,0.003999946,-0.0065253885,-0.0033514274,0.003085088,-0.0003703781,-0.003465078,-0.0054242075,0.0009584457,-0.005197831,0.003603162,0.0048823943,-0.00041171763,0.0009989656,-0.0040209224,0.002628903,-0.0003624089,-0.0002924401,-3.2498552e-05,0.0031572247,0.0026128257,-0.0022803256,-0.0030580086,-0.00357484,0.0042991657,-0.0015585661,0.00086751115,0.0004323435,0.0045290007,-0.0048501627,-0.001418146,0.00370478,0.003376496,0.006685608,0.00055006717,-0.0011108073,0.00024791225,0.0055819694,0.0041101393,-0.0041453117,-0.0011638473,0.0020769653,-8.08032e-06,-0.0002288826,0.0006749544,0.00035142386,-0.00043356852,-0.0029805794,-0.0017968996,0.0010227,0.006042389,0.0017817094,-0.0056505343,0.004619073,0.0023046366,0.0027151196,0.0020018944,-0.00041239324,-0.00031199362,0.0050316383,-0.0041035055,0.001887646,0.0069080763,0.0039198315,-0.0003352705,-0.0012968663,-0.0009449865,-0.0052614617,0.004834936,-0.0014728566,-0.0017496345,-0.0008812858,0.00056978094,-0.005053855,-0.0017934664,0.0021964775,-0.008228115,0.0029420764,0.0012297969,-0.0038868873,-0.0003670447,0.0032279065,-0.0016167451,0.0036267326
These are the 3 codes in order:
let DCTSetupForward = vDSP_DCT_CreateSetup(nil,
vDSP_Length(numberSamples),
vDSP_DCT_Type.II)
var output = Array<Float>(repeating:0.0,
count: numberSamples)
vDSP_DCT_Execute(DCTSetupForward!, data, &output)
func dctA (_ data:[Float] = []) -> Array<Float> {
let numberSamples = data.count
var c = [Float](repeating: 0,
count: numberSamples)
for i in 0..< numberSamples {
var sum : Float = 0
let s : Float = (i == 0) ? sqrt(0.5) : 1
for j in 0..< numberSamples {
sum = sum + s * data[j] * cos(Float.pi * (numberSamples + 0.5) * Float(i) / numberSamples)
}
c[i] = sum * sqrt(2.0 / numberSamples)
}
return c;
}
func dctB (_ data:[Float] = []) -> Array<Float> {
var angle : Float
var c :[Float] = []
let numberSamples = data.count
for i in 0..<numberSamples {
c.append(0)
for j in 0..< numberSamples {
let fk = Float(2*j + 1)
let y = Float.pi * Float(i) * fk
let fky = fk * y
let x = Float(2 * numberSamples)
angle = fky / x
c[i] = c[i] + cos ( angle ) * data[j];
}
c[i] = c[i] * sqrt (2.0/Float(numberSamples));
}
return c;
}
I have noticed the difference in the two last codes. So, I have 3 questions:
Why am I having 3 different results for the DCT of this data?
Can someone with mathlab check which is the right one?
why the difference in the last two codes?
Searching through Wikipedia and the formula of the above are different for typeII.
If you following the corrected one below, the error mainly comes from rounding during multiplying and summation.
let DCTSetupForward = vDSP_DCT_CreateSetup(nil,
vDSP_Length(numberSamples),
vDSP_DCT_Type.II)
var output = Array<Float>(repeating:0.0,
count: numberSamples)
vDSP_DCT_Execute(DCTSetupForward!, data, &output)
print(output)
func dctA (_ data:[Float] = []) -> Array<Float> {
let numberSample = data.count
var c = [Float](repeating: 0,
count: numberSample)
for i in 0..<numberSample {
var sum : Float = 0
let s : Float = (i == 0) ? 1 : 1
for j in 0..<numberSample {
sum = sum + s * data[j] * cos(Float.pi * (Float(j) + 0.5) * Float(i) / Float(numberSample))
}
c[i] = sum
}
return c;
}
func dctB (_ data:[Float] = []) -> Array<Float> {
var angle : Float
var c :[Float] = []
let numberSampl = data.count
for i in 0..<numberSampl {
c.append(0)
for j in 0..<numberSampl {
let fk = Float(2*j + 1)
let y = Float.pi * Float(i) * fk
// let fky = fk * y
let x = Float(2 * numberSampl)
angle = y / x
c[i] = c[i] + cos ( angle ) * data[j];
}
}
return c;
}

CoreImage doesn't implement filter to the image

My image for the first time looks like:
After pressing "Apply the Filter" button it becomes:
and I implement this ColorCube:
How you see, it implements color-cube, but very very insensibly.
This is my code:
func colorCubeFilterFromLUT(imageName : NSString) -> CIFilter? {
let kDimension : UInt = 64
let lutImage = UIImage(named: imageName as String)!.CGImage
let lutWidth: UInt = UInt(CGImageGetWidth(lutImage!))
let lutHeight: UInt = UInt(CGImageGetHeight(lutImage!))
let rowCount = lutHeight / kDimension
let columnCount = lutWidth / kDimension
if ((lutWidth % kDimension != 0) || (lutHeight % kDimension != 0) || (rowCount * columnCount != kDimension)) {
NSLog("Invalid colorLUT %#", imageName);
return nil
}
let bitmap = self.createRGBABitmapFromImage(lutImage!)
let size = Int(kDimension) * Int(kDimension) * Int(kDimension) * sizeof(Float) * 4
let data = UnsafeMutablePointer<Float>(malloc(Int(size)))
var bitmapOffset : Int = 0
var z : UInt = 0
for (var row: UInt = 0; row < rowCount; row++)
{
for (var y: UInt = 0; y < kDimension; y++)
{
var tmp = z
for (var col: UInt = 0; col < columnCount; col++)
{
for (var x: UInt = 0; x < kDimension; x++) {
let alpha = Float(bitmap[Int(bitmapOffset)]) / 255.0
let red = Float(bitmap[Int(bitmapOffset+1)]) / alpha
let green = Float(bitmap[Int(bitmapOffset+2)]) / alpha
let blue = Float(bitmap[Int(bitmapOffset+3)]) / alpha
var dataOffset = Int(z * kDimension * kDimension + y * kDimension + x) * 4
data[dataOffset] = red
data[dataOffset + 1] = green
data[dataOffset + 2] = blue
data[dataOffset + 3] = alpha
bitmapOffset += 4
}
z++
}
z = tmp
}
z += columnCount
}
let colorCubeData = NSData(bytesNoCopy: data, length: size, freeWhenDone: true)
// create CIColorCube Filter
var filter = CIFilter(name: "CIColorCube")
filter!.setValue(colorCubeData, forKey: "inputCubeData")
filter!.setValue(kDimension, forKey: "inputCubeDimension")
return filter
}
func createRGBABitmapFromImage(inImage: CGImage) -> UnsafeMutablePointer<Float> {
let pixelsWide = CGImageGetWidth(inImage)
let pixelsHigh = CGImageGetHeight(inImage)
let bitmapBytesPerRow = Int(pixelsWide) * 4
let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapData = malloc(Int(CUnsignedLong(bitmapByteCount))) // bitmap
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue)
let context = CGBitmapContextCreate(bitmapData, 512, 512, 8, Int(bitmapBytesPerRow), colorSpace, bitmapInfo.rawValue)
let rect = CGRect(x:0, y:0, width:1000, height:1000)
CGContextDrawImage(context, rect, inImage)
var convertedBitmap = malloc(Int(bitmapByteCount * sizeof(Float)))
print("BBB \(convertedBitmap)")
vDSP_vfltu8(UnsafePointer<UInt8>(bitmapData), 1, UnsafeMutablePointer<Float>(convertedBitmap), 1, vDSP_Length(bitmapByteCount))
free(bitmapData)
return UnsafeMutablePointer<Float>(convertedBitmap)
}
I'm working over it from the morning and nothing. I cannot find why this filter does not implements to my image.

Core Graphics messing changes UIimage format

I wrote a simple algorithm that detects the edges in the UIImages. It works perfectly fine with the images taken from bundle (look at first image).
After I am doing some image manipulations (apply filters, masks, crop and etc) and I pass the image to the same function it comes up messed up (image 2). I assume that that the CoreGrahics is changing something internally in the image. The question is what?
That's how I start processing the image:
public struct PixelData {
var a:UInt8 = 255
var r:UInt8
var g:UInt8
var b:UInt8
}
func findEdges(cgImage:CGImageRef)->UIImage{
var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage))
//var data = CFDataGetMutableBytePtr
var mdata: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
var data = UnsafeMutablePointer<UInt8>(mdata)
let height = CGImageGetHeight(cgImage)
let width = CGImageGetWidth(cgImage)
var start = CACurrentMediaTime()
//create an empty buffer
let emptyPixel = PixelData(a: 0, r: 0, g: 0, b: 0)
let blackPixel = PixelData(a: 255, r: 255, g: 255, b: 255)
var buffer = [PixelData](count: Int(width * height), repeatedValue: emptyPixel)
var booleanArray = [Bool](count: Int(width * height), repeatedValue: false)
for var y = 0; y < height-1; y++ {
for var x = 0; x < width; x++ {
//Current one
var currentPixelInfo: Int = ((Int(width) * Int(y)) + Int(x)) * 4
var currentAlpha = CGFloat(data[currentPixelInfo+3]) / CGFloat(255.0)
var downPixelInfo: Int = ((Int(width) * Int(y+1)) + Int(x)) * 4
var downAlpha = CGFloat(data[downPixelInfo+3]) / CGFloat(255.0)
if y == 0 && currentAlpha != 0{ // Top Edge
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
if y > 0 && y < height - 2{
//one up
var topPixelInfo: Int = ((Int(width) * Int(y - 1)) + Int(x )) * 4
var topAlpha = CGFloat(data[topPixelInfo+3]) / CGFloat(255.0)
if downAlpha == 0 && currentAlpha != 0 {//edge
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
if topAlpha == 0 && currentAlpha != 0 {//edge
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
}
if y == height - 2 && downAlpha != 0 {
booleanArray[downPixelInfo/4] = true
buffer[downPixelInfo/4] = blackPixel
}
}
}
for var y = 0; y < height-1; y++ {
for var x = 0; x < width-1; x++ {
//Current one
var currentPixelInfo: Int = ((Int(width) * Int(y)) + Int(x)) * 4
var currentAlpha = CGFloat(data[currentPixelInfo+3]) / CGFloat(255.0)
//Next
var nextPixelInfo: Int = ((Int(width) * Int(y)) + Int(x + 1)) * 4
var nextAlpha = CGFloat(data[nextPixelInfo+3]) / CGFloat(255.0)
//check horizontally
if x == 0 && currentAlpha != 0{ // Edge case
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
if x > 0 && x < width - 2{
//One before
var previousPixelInfo: Int = ((Int(width) * Int(y)) + Int(x - 1)) * 4
var previousAlpha = CGFloat(data[previousPixelInfo+3]) / CGFloat(255.0)
if nextAlpha == 0 && currentAlpha != 0 {//Living on the edge
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
if previousAlpha == 0 && currentAlpha != 0 {//Living on the edge
booleanArray[currentPixelInfo/4] = true
buffer[currentPixelInfo/4] = blackPixel
}
}
if x == width - 2 && nextAlpha != 0 {
booleanArray[nextPixelInfo/4] = true
buffer[nextPixelInfo/4] = blackPixel
}
}
}
var stop = CACurrentMediaTime()
let image = imageFromARGB32Bitmap(buffer, width: width, height: height)
println(stop - start)
return image!;
//self.imageView.image = image
}
func imageFromARGB32Bitmap(pixels:[PixelData], width:Int, height:Int)->UIImage? {
let bitsPerComponent:Int = 8
let bitsPerPixel:Int = 32
assert(pixels.count == Int(width * height))
var data = pixels // Copy to mutable []
let providerRef = CGDataProviderCreateWithCFData(
NSData(bytes: &data, length: data.count * sizeof(PixelData))
)
// let redPixel = PixelData(a: 255, r: 192, g: 0, b: 0)
let cgim = CGImageCreate(
width,
height,
bitsPerComponent,
bitsPerPixel,
width * Int(sizeof(PixelData)),
rgbColorSpace,
bitmapInfo,
providerRef,
nil,
true,
kCGRenderingIntentDefault
)
return UIImage(CGImage: cgim)
}
[][3]
Although I didn't figure out what exactly UIImage is doing to raw pixel data, the function that I wrote fixes the problem. Key point here is using CGImageAlphaInfo.PremultipliedFirst value of bitmap info since my data structure is expecting ARGB format.
func imageFromBitmapContext(image:CGImageRef, width:Int, height:Int)->UIImage?
{
let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.rawValue)
let bytesPerRow = 4 * width
let context = CGBitmapContextCreate(nil, Int(width), Int(height), 8, Int(bytesPerRow), colorSpace, bitmapInfo)
CGContextDrawImage(context, CGRectMake(0, 0, CGFloat(width), CGFloat(height)), image)
let image = CGBitmapContextCreateImage(context)
return UIImage(CGImage: image)
}

iOS Swift Flood fill algorithm

I created this extension for "bucket fill" (flood fill) of touch point:
extension UIImageView {
func bucketFill(startPoint: CGPoint, newColor: UIColor) {
var newRed, newGreen, newBlue, newAlpha: CUnsignedChar
let pixelsWide = CGImageGetWidth(self.image!.CGImage)
let pixelsHigh = CGImageGetHeight(self.image!.CGImage)
let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))
let bitmapBytesPerRow = Int(pixelsWide) * 4
var context = self.image!.createARGBBitmapContext()
//Clear the context
CGContextClearRect(context, rect)
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, rect, self.image!.CGImage)
var data = CGBitmapContextGetData(context)
var dataType = UnsafeMutablePointer<UInt8>(data)
let newColorRef = CGColorGetComponents(newColor.CGColor)
if(CGColorGetNumberOfComponents(newColor.CGColor) == 2) {
newRed = CUnsignedChar(newColorRef[0] * 255) // CUnsignedChar
newGreen = CUnsignedChar(newColorRef[0] * 255)
newBlue = CUnsignedChar(newColorRef[0] * 255)
newAlpha = CUnsignedChar(newColorRef[1])
} else {
newRed = CUnsignedChar(newColorRef[0] * 255)
newGreen = CUnsignedChar(newColorRef[1] * 255)
newBlue = CUnsignedChar(newColorRef[2] * 255)
newAlpha = CUnsignedChar(newColorRef[3])
}
let newColorStr = ColorRGB(red: newRed, green: newGreen, blue: newBlue)
var stack = Stack()
let offset = 4*((Int(pixelsWide) * Int(startPoint.y)) + Int(startPoint.x))
//let alpha = dataType[offset]
let startRed: UInt8 = dataType[offset+1]
let startGreen: UInt8 = dataType[offset+2]
let startBlue: UInt8 = dataType[offset+3]
stack.push(startPoint)
while(!stack.isEmpty()) {
let point: CGPoint = stack.pop() as! CGPoint
let offset = 4*((Int(pixelsWide) * Int(point.y)) + Int(point.x))
let alpha = dataType[offset]
let red: UInt8 = dataType[offset+1]
let green: UInt8 = dataType[offset+2]
let blue: UInt8 = dataType[offset+3]
if (red == newRed && green == newGreen && blue == newBlue) {
continue
}
if (red.absoluteDifference(startRed) < 4 && green.absoluteDifference(startGreen) < 4 && blue.absoluteDifference(startBlue) < 4) {
dataType[offset] = 255
dataType[offset + 1] = newRed
dataType[offset + 2] = newGreen
dataType[offset + 3] = newBlue
if (point.x > 0) {
stack.push(CGPoint(x: point.x - 1, y: point.y))
}
if (point.x < CGFloat(pixelsWide)) {
stack.push(CGPoint(x: point.x + 1, y: point.y))
}
if (point.y > 0) {
stack.push(CGPoint(x: point.x, y: point.y - 1))
}
if (point.y < CGFloat(pixelsHigh)) {
stack.push(CGPoint(x: point.x, y: point.y + 1))
}
} else {
}
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
let finalContext = CGBitmapContextCreate(data, pixelsWide, pixelsHigh, CLong(8), CLong(bitmapBytesPerRow), colorSpace, bitmapInfo)
let imageRef = CGBitmapContextCreateImage(finalContext)
self.image = UIImage(CGImage: imageRef, scale: self.image!.scale,orientation: self.image!.imageOrientation)
}
}
Now I would like to improve performance. How can I make this algorithm work faster? UInt8.absoluteDifference extension is my attempt to include almost same colors to flood fill and it's working but this could be really improve and I know it but I don't know how.
extension UInt8 {
func absoluteDifference(subtrahend: UInt8) -> UInt8 {
if (self > subtrahend) {
return self - subtrahend;
} else {
return subtrahend - self;
}
}
}
My Stack class:
class Stack {
var count: Int = 0
var head: Node = Node()
init() {
}
func isEmpty() -> Bool {
return self.count == 0
}
func push(value: Any) {
if isEmpty() {
self.head = Node()
}
var node = Node(value: value)
node.next = self.head
self.head = node
self.count++
}
func pop() -> Any? {
if isEmpty() {
return nil
}
var node = self.head
self.head = node.next!
self.count--
return node.value
}
}
Thanks for help

Resources