How can I convert UIImage to Byte Array In Swift 4 - ios

I'm trying to convert an UIimage to byte array in swift . I've searched a lot but the solutions are either too old ( for swift 2 ) or they don't work .
Does anyone know a way to do so ?!
Thanks

Solution above is incorrect, extremely slow to copy byte per byte
It took 4 seconds for a big image, and 0.02s with the following (new constructor from Swift3)
let data: [UInt8] = [...]
let image = UIImage(data: Data(bytes: data, count: data.count))
guard let dataPng: Data = image.pngData() else { return [] }
let finalData = [UInt8](dataPng)

Try this!!
guard let image = UIImage(named: "someImage") else { return }
let data = UIImageJPEGRepresentation(image, 1.0)
OR you can convert UIImage to NSData
func getArrayOfBytesFromImage(imageData:NSData) -> NSMutableArray
{
// the number of elements:
let count = data.length / MemoryLayout<UInt8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count)
var byteArray:NSMutableArray = NSMutableArray()
for (var i = 0; i < count; i++) {
byteArray.addObject(NSNumber(unsignedChar: bytes[i]))
}
return byteArray
}

Related

"Fatal error: Index out of range" while working with byte array in swift 4?

I have the following code like this,
extension Collection {
func element(at index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
class Example: UIViewController{
......
viewDidLoad(){..}
viewDidDisappear(){..}
func readandsend(){
let ReceiveData = rxCharacteristic?.value
if let ReceiveData = ReceiveData {
let ReceivedNoOfBytes = ReceiveData.count
myByteArray = [UInt8](repeating: 0, count: ReceivedNoOfBytes)
(ReceiveData as NSData).getBytes(&myByteArray, length: ReceivedNoOfBytes)
print("Data Received ",myByteArray)
}
//Now I'm storing all my bytearray data here
var first = myByteArray[0]
var sec = myByteArray[1]
var third = myByteArray[2]
var fourth = myByteArray[3]
//Here I'm trying to get past out of range using extension block shown above
if let b1 = myByteArray.element(at: 0){
one = myByteArray[0]
}
if let b2 = myByteArray.element(at: 1){
two = myByteArray[1]
}
if let b3 = myByteArray.element(at: 2){
three = myByteArray[2]
}
if let b4 = myByteArray.element(at: 3){
four = myByteArray[3]
}
//I have two textbox's from which I need to get the strings and convert to UInt8
var tb1 = textbox1.text
var b1 = tb1.flatMap{UInt8(String($0))}
var tb2 = textbox2.text
var b2 = tb2.flatMap{UInt8(String($0))}
//Now when I try sending my completed byte array
let completedArray = [UInt8]()
completedArray[0] = b1
completedArray[1] = b2
completedArray[2] = myByteArray[2]
completedArray[3] = myByteArray[3]
//Writing back to peripheral
let TransmitData = NSData(bytes: completedArray, length: completedArray.count)
peripheral.writeValue....so on
When I send it I'm getting an index out of range error, but have I properly used the extension block? Can someone pls help?
You need to either initialize the array with the necessary number of elements or append to the array.
Array Initialization:
let completedArray = [UInt8](count: 4)
completedArray[0] = b1
...
Append:
let completedArray = [UInt8]()
completedArray.append(b1)
...

i am converting an image to a byte array but fail to get an image from same byte array

I have two image views one image view is to show image pick from gallary and the the second image view is to show the image which is converted from NSData to [UINT8] and from [UINT8] to UIImage
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
importImage.image=info[UIImagePickerControllerOriginalImage] as? UIImage
let imageData:NSData = UIImageJPEGRepresentation(importImage.image!,1)!
let imageata=convertionofImageToByteArray(imageData)
let cadenaImagen=imageata as NSArray
convertedImage.image = convierteImagen(cadenaImagen)
}
the below method to convert an image to byte array
func convertionofImageToByteArray(imageData:NSData)->NSMutableArray{
let count = imageData.length / sizeof(UInt8)
// create array of appropriate length:
var bytes = [UInt8](count: count, repeatedValue: 0)
// copy bytes into array
imageData.getBytes(&bytes, length:count * sizeof(UInt8))
let byteArray:NSMutableArray = NSMutableArray()
for i in 0..<count{
byteArray.addObject(NSNumber(unsignedChar: bytes[i]))
}
return byteArray
}
the below method to convert byte array to image
func convierteImagen(cadenaImagen: NSArray) -> UIImage? {
var bytes = [UInt8]()
for i in 0..<cadenaImagen.count {
if let signedByte = Int8(String(cadenaImagen[i])) {
bytes.append(UInt8(bitPattern: signedByte))
} else {
// Do something with this error condition
}
}
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
return UIImage(data: datos) // Note it's optional. Don't force unwrap!!!
}
It is beyond me why you would think that typecasting unsigned byte to a signed byte would work. You actually even have a comment to handle the error there and it hits that error every time the overflow occurs (result is nil).
So try this:
func convierteImagen(cadenaImagen: NSArray) -> UIImage? {
var bytes = [UInt8]()
for i in 0..<cadenaImagen.count {
if let signed = UInt8(String(cadenaImagen[i])) {
bytes.append(signed)
} else {
// Do something with this error condition
}
}
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
return UIImage(data: datos) // Note it's optional. Don't force unwrap!!!
}
The statement if let signedByte = Int8(String(cadenaImagen[i])) { will fail for any value in bytes where value is larger then 127.

convert byte array to UIImage in Swift

I want to convert byte array to UIImage in my project.
For that I found something here.
After that I tried to convert that code in swift but failed.
Here is my swift version of the code.
func convierteImagen(cadenaImagen: NSMutableString) -> UIImage {
var strings: [AnyObject] = cadenaImagen.componentsSeparatedByString(",")
let c: UInt = UInt(strings.count)
var bytes = [UInt8]()
for (var i = 0; i < Int(c); i += 1) {
let str: String = strings[i] as! String
let byte: Int = Int(str)!
bytes.append(UInt8(byte))
// bytes[i] = UInt8(byte)
}
let datos: NSData = NSData(bytes: bytes as [UInt8], length: Int(c))
let image: UIImage = UIImage(data: datos)!
return image
}
but I'm getting error:
EXC_BAD_INSTRUCTION
which is displayed in screenshot as follow.
Please help to solve this problem.
If you are using the example data that you quoted, those values are NOT UInts - they are signed Ints. Passing a negative number into UInt8() does indeed seem to cause a runtime crash - I would have thought it should return an optional. The answer is to use the initialiser using the bitPattern: signature, as shown in the Playground example below:
let o = Int8("-127")
print(o.dynamicType) // Optional(<Int8>)
// It's optional, so we need to unwrap it...
if let x = o {
print(x) // -127, as expected
//let b = UInt8(x) // Run time crash
let b = UInt8(bitPattern: x) // 129, as it should be
}
Therefore your function should be
func convierteImagen(cadenaImagen: String) -> UIImage? {
var strings = cadenaImagen.componentsSeparatedByString(",")
var bytes = [UInt8]()
for i in 0..< strings.count {
if let signedByte = Int8(strings[i]) {
bytes.append(UInt8(bitPattern: signedByte))
} else {
// Do something with this error condition
}
}
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
return UIImage(data: datos) // Note it's optional. Don't force unwrap!!!
}

Convert UIImage to byte array in swift

How can I convert a UIimage into a Byte Array, so I can upload it into my web service?
You can actually use a couple of lines to do it
guard let image = UIImage(named: "someImage"),
let data = image.jpegData(compressionQuality: 1.0) else { return }
// OR
guard let image = UIImage(named: "someImage"),
let data = image.pngData() else { return }
The number should range from 0.0 to 1.0 and sets the jpeg quality. PNG is lossless so there is no need for compression quality identifier but be aware that the file size can be about 10 times higher
--- update ---
Updated for Swift 5.1
You can convert UIImage to NSData and pass it to this method
func getArrayOfBytesFromImage(imageData:NSData) -> NSMutableArray
{
// the number of elements:
let count = imageData.length / sizeof(UInt8)
// create array of appropriate length:
var bytes = [UInt8](count: count, repeatedValue: 0)
// copy bytes into array
imageData.getBytes(&bytes, length:count * sizeof(UInt8))
var byteArray:NSMutableArray = NSMutableArray()
for (var i = 0; i < count; i++) {
byteArray.addObject(NSNumber(unsignedChar: bytes[i]))
}
return byteArray
}
Swift 5, iOS 14 version based on toofani answer, minimal changes
func getArrayOfBytesFromImage(imageData:NSData) -> Array<UInt8>
{
// the number of elements:
let count = imageData.length / MemoryLayout<Int8>.size
// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count * MemoryLayout<Int8>.size)
var byteArray:Array = Array<UInt8>()
for i in 0 ..< count {
byteArray.append(bytes[i])
}
return byteArray
}
So a complete sequence looks like this... assuming I got a UIImage I extract the data and then recombine it.
let data = imageX.pngData()
bytes = getArrayOfBytesFromImage(imageData: data! as NSData)
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
newImage = UIImage(data: datos as Data) // Note it's optional. Don't force unwrap!!!

Swift language: How to call SecRandomCopyBytes

From Objective-C, I could do this:
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault, length, data.mutableBytes);
When attempting this in Swift, I have the following:
let data = NSMutableData(length: Int(length))
let result = SecRandomCopyBytes(kSecRandomDefault, length, data.mutableBytes)
but I get this compiler error:
'Void' is not identical to 'UInt8'
The data.mutableBytes parameter is rejected because the types do not match, but I can't figure out how to coerce the parameter (and I'm presuming it's somehow safe to do).
This appears to work:
let data = NSMutableData(length: Int(length))
let result = SecRandomCopyBytes(kSecRandomDefault, length, UnsafeMutablePointer<UInt8>(data.mutableBytes))
Swift 5
let count: Int = <byteCount>
var data = Data(count: count)
let result = data.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, count, $0.baseAddress!)
}
Swift 4:
var data = Data(count: <count>)
let result = data.withUnsafeMutableBytes { mutableBytes in
SecRandomCopyBytes(kSecRandomDefault, data.count, mutableBytes)
}
Swift 4 version:
let count = 16
var data = Data(count: count)
_ = data.withUnsafeMutableBytes {
SecRandomCopyBytes(kSecRandomDefault, count, $0)
}

Resources