Can I convert .png data into an Int in Swift? - swift

I convert an image into .png data from a UIImageView and print result on console with this code:
let img = img_view.image!.pngData()
print(img)
The result of this snippet is 232206 Bytes
Can I get only 232206 as integer output, without the "bytes" suffix?

That's the size (number of bytes) of the Data, which you can access by .count:
let sizeOfData = img.count // 232206
After all, Data represents a collection of bytes, so it conforms to Collection, which has the count property.

Use count property:
let imgData = imgView.image!.pngData()
let imgBytesCount = imgData!.count
print(imgBytesCount)

Related

how to read data from other Waves Oracles?

how to read data from other Waves Oracles?
getInteger(OracleAddress, key)
key is String
I don't know in what type OracleAddress i should convert to
I tried
let OracleAddress = Address("3NAcoeWdUTWn8csXJPG47v1Fjtjcfqxb5tu".toBytes())
but doesn't work
When you do toBytes() with string value you actually get bytes from UTF8 string, but in your case address is an array of bytes converted to base58, so you only need to decode it from base58:
let OracleAddress = Address(base58'3NAcoeWdUTWn8csXJPG47v1Fjtjcfqxb5tu')
getIntegerValue(OracleAddress, key)

AVAssetReader trouble getting pixel buffer from copyNextSampleBuffer(), Swift

I'm trying to read the image frames from a Quicktime movie file using AVFoundation and AVAssetReader on macOSX. I want to display the frames via a texture map in Metal. There are many examples of using AVAssetReader online, but I cannot get it working for what I want.
I can read the basic frame data from the movie -- the time values, size, and durations in the printout look correct. However, when I try to get the pixelBuffer, CMSampleBufferGetImageBuffer returns NULL.
let track = asset.tracks(withMediaType: AVMediaType.video)[0]
let videoReaderSettings : [String : Int] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)]
let output = AVAssetReaderTrackOutput(track:track, outputSettings:nil) // using videoReaderSettings causes it to no longer report frame data
guard let reader = try? AVAssetReader(asset: asset) else {exit(1)}
output.alwaysCopiesSampleData = true
reader.add(output)
reader.startReading()
while(reader.status == .reading){
if let sampleBuffer = output.copyNextSampleBuffer(), CMSampleBufferIsValid(sampleBuffer) {
let frameTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer)
if (frameTime.isValid){
print("frame: \(frameNumber), time: \(String(format:"%.3f", frameTime.seconds)), size: \(CMSampleBufferGetTotalSampleSize(sampleBuffer)), duration: \( CMSampleBufferGetOutputDuration(sampleBuffer).value)")
if let pixelBuffer : CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
getTextureFromCVBuffer(pixelBuffer)
// break
}
frameNumber += 1
}
}
}
This problem was addressed here (Why does CMSampleBufferGetImageBuffer return NULL) where it is suggested that the problem is that one must specify a video format in the settings argument instead of 'nil'. So I tried replacing 'nil' with 'videoReaderSettings' above, with various values for the format: kCVPixelFormatType_32BGRA, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, and others.
The result is that the frame 'time' values are still correct, but the 'size' and 'duration' values are 0. However, CMSampleBufferGetImageBuffer DOES return something, where before it was 0. But garbage shows up onscreen.
Here is the function which converts the pixelBuffer to a Metal texture.
func getTextureFromCVBuffer(_ pixelBuffer:CVPixelBuffer) {
// Get width and height for the pixel buffer
let width = CVPixelBufferGetWidth(pixelBuffer)
let height = CVPixelBufferGetHeight(pixelBuffer)
// Converts the pixel buffer in a Metal texture.
var cvTextureOut: CVMetalTexture?
if CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, self.textureCache!, pixelBuffer, nil, .bgra8Unorm, width, height, 0, &cvTextureOut) != kCVReturnSuccess {
print ("CVMetalTexture create failed!")
}
guard let cvTexture = cvTextureOut, let inputTexture = CVMetalTextureGetTexture(cvTexture) else {
print("Failed to create metal texture")
return
}
texture = inputTexture
}
When I'm able to pass a pixelBuffer to this function, it does report the correct size for the image. But as I said, what appears onscreen is garbage -- its composed of chunks of recent Safari browser pages actually. I'm not sure if the problem is in the first function or the second function. A nonzero return value from CMSampleBufferGetImageBuffer is encouraging, but the 0's for size and duration are not.
I found this thread (Buffer size of CMSampleBufferRef) which suggests that showing 0 for the size and duration may not be a problem, so maybe the issue is in the conversion to the Metal texture?
Any idea what I am doing wrong?
Thanks!
put videoReaderSetting at AVAssetReaderTrackOutput.
let videoReaderSettings : [String : Int] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)]
let output = AVAssetReaderTrackOutput(track:track, outputSettings: videoReaderSettings)

Order a NSURL array

I'm loading a lot of image paths into a NSURL.
The images are in a folder ordered from 1.PNG, 2.PNG, 3.PNG to 1500.PNG. When I trie to load them:
let imagePath = path + "/images"
let url = NSURL(fileURLWithPath: imagePath)
print(url)
let fileManager = NSFileManager.defaultManager()
let properties = [NSURLLocalizedLabelKey,
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey]
do {
imageURLs = try fileManager.contentsOfDirectoryAtURL(url, includingPropertiesForKeys: properties, options:NSDirectoryEnumerationOptions.SkipsHiddenFiles)
} catch let error1 as NSError {
print(error1.description)
}
The imageURLs array gets filled with:
imageURLs[0] = ...\0.PNG
imageURLs[1] = ...\1.PNG
imageURLs[2] = ...\100.PNG
imageURLs[3] = ...\1000.PNG
and not in the numeric order!
Can someone help to sort the imageURLs or while i load the image paths on it or after they are loaded?
As you want to sort the files by the number you have to parse first the path to achieve it, so let's suppose we have the following array of NSURL objects:
var urls = [NSURL(string: "file:///path/to/user/folder/2.PNG")!, NSURL(string: "file:///path/to/user/folder/100.PNG")!, NSURL(string: "file:///path/to/user/folder/101.PNG")!, NSURL(string: "file:///path/to/user/folder/1.PNG")! ]
We can use the pathComponents property to extract an array with all the components in the path for a NSURL (e.g ["/", "path", "to", "user", "folder", "2.PNG"]).
If we see we can order the files by the last element in the array that is the filename removing the extension and the dot("."), in this case the number. Let's see how to do it in the following code:
urls.sortInPlace {
// number of elements in each array
let c1 = $0.pathComponents!.count - 1
let c2 = $1.pathComponents!.count - 1
// the filename of each file
var v1 = $0.pathComponents![c1].componentsSeparatedByString(".")
var v2 = $1.pathComponents![c2].componentsSeparatedByString(".")
return Int(v1[0]) < Int(v2[0])
}
In the above code we use the function sortInPlace to avoid create another array with the elements sorted, but can you use sort instead if you want. The another important point in the code is the line return Int(v1[0]) < Int(v2[0]), in this line we have to convert the number in the string to a real number, because if we compare the two strings "2" and "100" the second one is less than greater than because the string are compared lexicographically.
So the the array urls should be like the following one:
[file:///path/to/user/folder/1.PNG, file:///path/to/user/folder/2.PNG, file:///path/to/user/folder/100.PNG, file:///path/to/user/folder/101.PNG]
EDIT:
The two functions pathComponents and componentsSeparatedByString increase the space complexity of the sortInPlace algorithm, if you can asure that the path for the files always will be the same except it's filename that should be a number you can use instead this code:
urls.sortInPlace { $0.absoluteString.compare(
$1.absoluteString, options: .NumericSearch) == .OrderedAscending
}
I hope this help you.
Its a bit late, anyway this worked for me in Swift 5
imageURLs.sort {
($0.pathComponents.last?.components(separatedBy: ".").first)! < ($1.pathComponents.last?.components(separatedBy: ".").first)!
}
This takes path components from url(separated by /), then take the last part and take components of it ( separated by . ). Then take first part and compare with the other urls similarly.
Complexity: O(n log n), where n is the length of the collection[ as per Apple doc]

Base64Encoding result string with "/" in Swift

I want to convert a UIImage to a string representation. I am using the following code:
let imageData = UIImagePNGRepresentation(resizedImage)
if let imageBase64 = imageData?.base64EncodedDataWithOptions(NSDataBase64EncodingOptions (rawValue: 0)) {
let strBase64:String = imageBase64.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
}
The resulting string looks something like:
aVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWZRQUFBRk5DQUlBQUFCNWNRcGdBQUFBQVhOU1IwSUFyczRjNlFBQUFCeHBSRTlVQUFBQUFnQUFBQUFBQUFDbkFBQUFLQUFBQUtjQUFBQ21BQUg4T0dIYnkwY0FBRUFBU1VSQlZIZ0J0TDMxbHh4SHR1L3JQK25kYzk5ZDU3NHpaK0I0NXN5Y0FkUFlIbnRNR3RzeWcyekpZdWdXWTNjTEd0UnFadTVxWm1abVptWUd0Vmp2RzdFemQwVmxabFZYeXpOZTN4VnJaMlJXU2ZybFUxOS9ZMGZrUzdQTEQrZFdIczZ2UGxwWWZieTQ5bVJwL2NueStxT1ZqY2ZRNnVZVGFHM3JxZFRqOWUwbkxyUzI5ZGdnRncrdmJ6LzdtZHE0LzN4bDQxRjljOXZBK0p5enI5TC81dlQzZHpyU3Y1SCtzU3Y0OTI0OFc5dDRqa0xxMmNxbVhjc2J6d3hhV245cTBOemEwL24xWnhnTm1sMTk0a3d6cTQ5VlRhODhZVTB0UDJ
But the format I am looking for should contain "/", like the following (a random image I found):
/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxMTEhUSEhMWFRUWGBcZGRgXFxcVFRgYFxUWFhcVFxgYHSggGBolGxcXITEhJSkrLi4uFx8zODMtNygtLisBCgoKDg0OGhAQGisdHx0tLS0tKy0tLS0tLSstLS0tLS0tLS0tKy0tLS0tLSstLS0tLSs3Ky0tKysrLSstKysrK//AABEIAMwAzAMBIgACEQEDEQH/xAAcAAABBAMBAAAAAAAAAAAAAAAGAgMEBQABBwj/xABCEAABAwIDBQUGAwYFBAMBAAABAgMRAAQSITEFBkFRYRMicYGRBzJCobHRFCPBUmKCk+HwM0NTctIVkqLxRGOyJP/
I don't know how to get the second format (containing the "/").
You're encoding it twice. Just do
let strBase64 = imageData?.base64EncodedStringWithOptions([])

Convert UInt8 Array to String

I have decrypted using AES (CrytoSwift) and am left with an UInt8 array. What's the best approach to covert the UInt8 array into an appripriate string? Casting the array only gives back a string that looks exactly like the array. (When done in Java, a new READABLE string is obtained when casting Byte array to String).
I'm not sure if this is new to Swift 2, but at least the following works for me:
let chars: [UInt8] = [ 49, 50, 51 ]
var str = String(bytes: chars, encoding: NSUTF8StringEncoding)
In addition, if the array is formatted as a C string (trailing 0), these work:
str = String.fromCString(UnsafePointer(chars)) // UTF-8 is implicit
// or:
str = String(CString: UnsafePointer(chars), encoding: NSUTF8StringEncoding)
I don't know anything about CryptoSwift. But I can read the README:
For your convenience CryptoSwift provides two function to easily convert array of bytes to NSData and other way around:
let data = NSData.withBytes([0x01,0x02,0x03])
let bytes:[UInt8] = data.arrayOfBytes()
So my guess would be: call NSData.withBytes to get an NSData. Now you can presumably call NSString(data:encoding:) to get a string.
SWIFT 3.1
Try this:
let decData = NSData(bytes: enc, length: Int(enc.count))
let base64String = decData.base64EncodedString(options: .lineLength64Characters)
This is string output
Extensions allow you to easily modify the framework to fit your needs, essentially building your own version of Swift (my favorite part, I love to customize). Try this one out, put at the end of your view controller and call in viewDidLoad():
func stringToUInt8Extension() {
var cache : [UInt8] = []
for byte : UInt8 in 97..<97+26 {
cache.append(byte)
print(byte)
}
print("The letters of the alphabet are \(String(cache))")
}
extension String {
init(_ bytes: [UInt8]) {
self.init()
for b in bytes {
self.append(UnicodeScalar(b))
}
}
}