Convert UIImage to byte array in swift - ios

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!!!

Related

Data to Buffers

If you had a file stored as data which is much larger than your buffer and you wanted to iterate over this data in pieces of a buffer size, what is a good way to do this? If you could provide some context, that would be great.
I was thinking,
let bufferSize: Int = 20000
let myData: Data = Data(..)
var buffer: ??? = ???
var theOffset: ??? = ???
func runWhenReady() {
buffer = &myData
let amount = sendingData(&buffer[bufferOffset] maxLength: bufferSize - bufferOffset)
bufferOffset += amount
}
// pseudocode
// from foundation, but changed a bit (taken from Obj-C foundations just for types)
// writes the bytes from the specified buffer to the stream up to len bytes. Returns the number of bytes actually written.
func sendingData(_ buffer: const uint8_t *, maxLength len: NSUInteger) -> Int {
...
}
If you want to iterate you need a loop.
This is an example to slice the data in chunks of bufferSize with stride.
let bufferSize = 20000
var buffer = [UInt8]()
let myData = Data(..)
let dataCount = myData.count
for currentIndex in stride(from: 0, to: dataCount, by: bufferSize) {
let length = min(bufferSize, dataCount - currentIndex) // ensures that the last chunk is the remainder of the data
let endIndex = myData.index(currentIndex, offsetBy: length)
buffer = [UInt8](myData[currentIndex..<endIndex])
// do something with buffer
}
Open the file
let fileUrl: URL = ...
let fileHandle = try! FileHandle(forReadingFrom: fileUrl)
defer {
fileHandle.closeFile()
}
Create buffer:
let bufferSize = 20_000
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer {
buffer.deallocate()
}
Read until end of file is reached:
while true {
let bytesRead = read(fileHandle.fileDescriptor, buffer, bufferSize)
if bytesRead < 0 {
// handle error
break
}
if bytesRead == 0 {
// end of file
break
}
// do something with data in buffer
}

How can I convert UIImage to Byte Array In Swift 4

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
}

"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!!!
}

Resources