I have UIImage (got from Parse - convert variable PFFile).
How can I save and load image from this variable?
let a = object["image"] as! PFFile
a.getDataInBackgroundWithBlock({ (data:NSData?, error:NSError?) -> Void in
if (error == nil) {
// I have image, but the next I don't know what I do
let image = UIImage(data:data!)
}
})
Save image png
func saveImage(image:UIImage,name:String){
let selectedImage: UIImage = image
let data:NSData = UIImagePNGRepresentation(selectedImage)
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let success = fileManager.createFileAtPath(path, contents: data, attributes: nil)
print(success)
// Check image saved successfully
let getImagePath = (path as NSString).stringByAppendingPathComponent(name)
if fileManager.fileExistsAtPath(getImagePath) {
// image save success
let image = UIImage(contentsOfFile: getImagePath)!
}
else{
// image save error
}
}
Save other file
static func saveFile(fileData:NSData,name:String)->Bool{
let success = NSFileManager.defaultManager().createFileAtPath(path+"/"+name, contents: fileData, attributes: nil)
return success
}
Related
I have a string file that contains base64string of image. I'm sure that base64String is correct, because i used the website for checking:
https://codebeautify.org/base64-to-image-converter
with file data:
https://www.dropbox.com/s/10zjyzgcyv7s08m/data_base.txt?dl=1
(download and copy the content to the above website to generate the image )
But, On IOS Device , i can't convert it to image . This is my code (Swift3) :
if let filepath = Bundle.main.path(forResource: "data_base", ofType: "txt") {
do {
let text3 = try String(contentsOfFile: filepath, encoding: String.Encoding.utf8)
let dataDecoded : Data = Data(base64Encoded: text3, options: .ignoreUnknownCharacters)!
let decodedimage = UIImage(data: dataDecoded)
self.imageView.image = decodedimage
} catch {
}
}else {
print("file is not exist")
}
Please help me to find out the solution.
I'm trying to download video preview base on remote video URL. In my project, the server cannot return snapshot image of the videos, that's why I have to do it manually.
In table view, I have code like this in cellForItemAt to get video preview
DataManager.sharedInstance.getCachedImage(url: movie.url!, handler: { (image) in
cell.ivCover.image = image
})
and my getCachedImage function in DataManager:
func getCachedImage(url: String, handler: #escaping(_ result:UIImage) -> Void){
DispatchQueue.global().async {
let userDefaults = UserDefaults.standard
if let imageData = userDefaults.object(forKey: url){
if let finalImg = UIImage(data: imageData as! Data){
DispatchQueue.main.async {
handler(finalImg)
}
print("USING CACHED IMG")
}else{
DispatchQueue.main.async {
handler(#imageLiteral(resourceName: "cover"))
}
print("Cannot parse cached data to image. Use default")
}
}else{
let asset = AVURLAsset(url: URL(string: url)!)
let generate = AVAssetImageGenerator(asset: asset)
generate.appliesPreferredTrackTransform = true
var thumbTime = asset.duration
thumbTime.value = 1
var imgRef:CGImage?
do{
print("Downloading thum from url: \(url)")
imgRef = try generate.copyCGImage(at: thumbTime, actualTime: nil)
}catch let error{
print("Error download thum: \(error.localizedDescription)")
}
var finalImg:UIImage
if let _ = imgRef{
finalImg = UIImage(cgImage: imgRef!)
userDefaults.set(UIImagePNGRepresentation(finalImg), forKey: url)
}else{
finalImg = #imageLiteral(resourceName: "cover")
print("Download thumnail failed. Use default")
}
DispatchQueue.main.async {
handler(finalImg)
}
}
}
}
The problem is that, sometimes I scroll the Collection view, UI is freezed, sometimes it's not. Please note that this video is on REMOTE SERVER, NOT local video.
I've spent days to figure out the issue but still not able to find out what went wrong. Please help!
Or is there any existing library I can use?
import UIKit
import Photos
class ImportViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func myButton(_ sender: Any) {
let videoURL = "https://youerdomin.com/file.mp4"
print("1")
DispatchQueue.global(qos: .background).async {
print("2")
if let url = URL(string: videoURL), let urlData = NSData(contentsOf: url) {
print("3")
let documentsPath =
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(documentsPath)/tempFile.mp4"
DispatchQueue.main.async {
print("4")
urlData.write(toFile: filePath, atomically: true)
PHPhotoLibrary.shared().performChanges({
print("5")
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
}) { completed, error in
print("6")
if completed {
print("Video is saved!")
}else{
print("7: ",filePath)
}
}
}
}else{
print("8")
}
}
}
}
I cannot figure out why im getting this error.
This is the function to update a guest(Participant). I'm trying to save the Qr code i created to a PFFile and save to parse.
func update() {
_ = LabelText
let query = PFQuery(className: "Participant")
query.getObjectInBackgroundWithId(LabelText) {
(Update: PFObject?, error: NSError?) -> Void in
Update!["firstname"] = self.firstnameTF!.text
Update!["lastname"] = self.lastnameTF!.text
Update!["grade"] = self.gradeTF!.text
Update!["teacher"] = self.teacherTF.text
Update!["email"] = self.emailTF.text
Update!["phone"] = self.phoneTF.text
Update!["transportation"] = self.transportationTF.text
Update!.saveInBackground()
print("updated")
if self.QrImage == nil {
print("Image is Blank")
return
}else{
//Image is not blank
let imageData = UIImageJPEGRepresentation(self.QrImage!, 1)
let parseImageFile = PFFile(data: imageData!)
Update!.setObject(parseImageFile!, forKey: "qrcode")
Update!.saveInBackgroundWithBlock( {
(success: Bool , error: NSError?) -> Void in
})
}
self.dismissViewControllerAnimated(true, completion: {});
}
}
I can see the image in the self.QrImage field and i only get the error on:
let parseImageFile = PFFile(data: imageData!)
Why am i getting a nil error when it should have a value there?
Edit 1:
let imageData = UIImagePNGRepresentation(self.QrImage!)
let parseImageFile = PFFile(data: imageData!)
Update!.setObject(parseImageFile!, forKey: "qrcode")
Update!.saveInBackgroundWithBlock( {
(success: Bool , error: NSError?) -> Void in
})
}
Same result."fatal error: unexpectedly found nil while unwrapping an Optional value"
Edit 2:
So it seems there must be a name value associated with the image before you upload it to parse. My Image is of a Qrcode i create from other data. here's my code:
func displayQrCode() {
print(self.qrdata.text)
let data = self.qrdata.text!.dataUsingEncoding(NSISOLatin1StringEncoding)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter!.setValue(data, forKey: "inputMessage")
filter!.setValue("Q", forKey: "inputCorrectionLevel")
self.qrcodeImage = filter!.outputImage!
let scaleX = qrCode.frame.size.width / qrcodeImage!.extent.size.width
let scaleY = qrCode.frame.size.height / qrcodeImage!.extent.size.height
let transformedImage = qrcodeImage!.imageByApplyingTransform(CGAffineTransformMakeScale(scaleX, scaleY))
self.qrCode.image = UIImage(CIImage: transformedImage)
print("QRCode Made")
}
now i guess i need to add a name to the self.qrCode.image?
This is what needs to be done before you use UIImagePNGRepresentation:
self.QrImage = UIImage(named: "qrcode.png")
I am trying to read/display an image from Firebase. I am first encoding the image and then posting this encoded String to Firebase. This runs fine. When I try and decode the encoded string from Firebase and convert it to an image, I am getting a nil value exception.
This is how I am saving the image to Firebase
var base64String: NSString!
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
var uploadImage = image as! UIImage
var imageData = UIImagePNGRepresentation(uploadImage)!
self.base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let ref = Firebase(url: "https://XXX.firebaseio.com")
var quoteString = ["string": self.base64String]
var usersRef = ref.childByAppendingPath("goalImages")
var users = ["image": quoteString]
usersRef.setValue(users)
displayAlert("Image Posted", message: "Your image has been successfully posted!")
}
This is how I am trying to read the image from Firebase
// ViewController.swift
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var image: UIImageView!
var base64String: NSString!
#IBAction func buttonClicked(sender: AnyObject) {
sender.setTitle("\(sender.tag)", forState: UIControlState.Normal)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let ref = Firebase(url: "https://XXX.firebaseio.com/goalImages/image/string")
ref.observeEventType(.Value, withBlock: { snapshot in
self.base64String = snapshot.value as! NSString
let decodedData = NSData(base64EncodedString: self.base64String as String, options: NSDataBase64DecodingOptions())
//Next line is giving the error
var decodedImage = UIImage(data: decodedData!)
self.image.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The error says: "fatal error: unexpectedly found nil while unwrapping an Optional value"; decodedData is nil. Could someone explain what is going wrong.
Instead of
let decodedData = NSData(base64EncodedString: self.base64String as String,
options: NSDataBase64DecodingOptions())
try adding IgnoreUnknownCharacters
NSDataBase64DecodingOptions.IgnoreUnknownCharacters
Use Example: Encode a jpg, store and read from firebase
encode and write our favorite starship
if let image = NSImage(named:"Enterprise.jpeg") {
let imageData = image.TIFFRepresentation
let base64String = imageData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
let imageRef = myRootRef.childByAppendingPath("image_path")
imageRef.setValue(base64String)
read and decode
imageRef.observeEventType(.Value, withBlock: { snapshot in
let base64EncodedString = snapshot.value
let imageData = NSData(base64EncodedString: base64EncodedString as! String,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = NSImage(data:imageData!)
self.myImageView.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
EDIT 2019_05_17
Update to Swift 5 and Firebase 6
func writeImage() {
if let image = NSImage(named:"Enterprise.jpg") {
let imageData = image.tiffRepresentation
if let base64String = imageData?.base64EncodedString() {
let imageRef = self.ref.child("image_path")
imageRef.setValue(base64String)
}
}
}
func readImage() {
let imageRef = self.ref.child("image_path")
imageRef.observeSingleEvent(of: .value, with: { snapshot in
let base64EncodedString = snapshot.value as! String
let imageData = Data(base64Encoded: base64EncodedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
let decodedImage = NSImage(data: imageData)
self.myImageView.image = decodedImage
})
}
Firebase Engineer here:
I highly recommend using the new Firebase Storage API for uploading images to Firebase. It's simple to use, low cost, and backed by Google Cloud Storage for huge scale.
You can upload from NSData or an NSURL pointing to a local file (I'll show NSData, but the principle is the same):
// Data in memory
let data: NSData = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
// This can be stored in the Firebase Realtime Database
// It can also be used by image loading libraries like SDWebImage
}
}
You can even pause and resume uploads, and you can easily monitor uploads for progress:
// Upload data
let uploadTask = storageRef.putData(...)
// Add a progress observer to an upload task
uploadTask.observeStatus(.Progress) { snapshot in
// Upload reported progress
if let progress = snapshot.progress {
let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
}
}
Previous, I have ask for how to attach video then send via email. Now it working. Advised by some friend from this website.
I found new problem that video size is very large and larger than send with default email app in iOS for same video file.
Please advice me how to compress video file before attach to an email application.
Thank you everyone.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
if let myImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
image = info[UIImagePickerControllerOriginalImage] as! UIImage
self.dismissViewControllerAnimated(false, completion: nil)
sendmail()
}
else {
//picker.videoQuality = UIImagePickerControllerQualityTypeLow
videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
self.dismissViewControllerAnimated(true, completion: nil)
sendmailVDO()
}
}
Below is the code for Compress video by half of the actual size
var assetWriter:AVAssetWriter?
var assetReader:AVAssetReader?
let bitrate:NSNumber = NSNumber(value:250000)
func compressFile(urlToCompress: URL, outputURL: URL, completion:#escaping (URL)->Void){
//video file to make the asset
var audioFinished = false
var videoFinished = false
let asset = AVAsset(url: urlToCompress);
let duration = asset.duration
let durationTime = CMTimeGetSeconds(duration)
print("Video Actual Duration -- \(durationTime)")
//create asset reader
do{
assetReader = try AVAssetReader(asset: asset)
} catch{
assetReader = nil
}
guard let reader = assetReader else{
fatalError("Could not initalize asset reader probably failed its try catch")
}
let videoTrack = asset.tracks(withMediaType: AVMediaType.video).first!
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!
let videoReaderSettings: [String:Any] = [(kCVPixelBufferPixelFormatTypeKey as String?)!:kCVPixelFormatType_32ARGB ]
// ADJUST BIT RATE OF VIDEO HERE
let videoSettings:[String:Any] = [
AVVideoCompressionPropertiesKey: [AVVideoAverageBitRateKey:self.bitrate],
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoHeightKey: videoTrack.naturalSize.height,
AVVideoWidthKey: videoTrack.naturalSize.width
]
let assetReaderVideoOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: videoReaderSettings)
let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: nil)
if reader.canAdd(assetReaderVideoOutput){
reader.add(assetReaderVideoOutput)
}else{
fatalError("Couldn't add video output reader")
}
if reader.canAdd(assetReaderAudioOutput){
reader.add(assetReaderAudioOutput)
}else{
fatalError("Couldn't add audio output reader")
}
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: nil)
let videoInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
videoInput.transform = videoTrack.preferredTransform
//we need to add samples to the video input
let videoInputQueue = DispatchQueue(label: "videoQueue")
let audioInputQueue = DispatchQueue(label: "audioQueue")
do{
assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: AVFileType.mov)
}catch{
assetWriter = nil
}
guard let writer = assetWriter else{
fatalError("assetWriter was nil")
}
writer.shouldOptimizeForNetworkUse = true
writer.add(videoInput)
writer.add(audioInput)
writer.startWriting()
reader.startReading()
writer.startSession(atSourceTime: kCMTimeZero)
let closeWriter:()->Void = {
if (audioFinished && videoFinished){
self.assetWriter?.finishWriting(completionHandler: {
print("------ Finish Video Compressing")
self.checkFileSize(sizeUrl: (self.assetWriter?.outputURL)!, message: "The file size of the compressed file is: ")
completion((self.assetWriter?.outputURL)!)
})
self.assetReader?.cancelReading()
}
}
audioInput.requestMediaDataWhenReady(on: audioInputQueue) {
while(audioInput.isReadyForMoreMediaData){
let sample = assetReaderAudioOutput.copyNextSampleBuffer()
if (sample != nil){
audioInput.append(sample!)
}else{
audioInput.markAsFinished()
DispatchQueue.main.async {
audioFinished = true
closeWriter()
}
break;
}
}
}
videoInput.requestMediaDataWhenReady(on: videoInputQueue) {
//request data here
while(videoInput.isReadyForMoreMediaData){
let sample = assetReaderVideoOutput.copyNextSampleBuffer()
if (sample != nil){
let timeStamp = CMSampleBufferGetPresentationTimeStamp(sample!)
let timeSecond = CMTimeGetSeconds(timeStamp)
let per = timeSecond / durationTime
print("Duration --- \(per)")
DispatchQueue.main.async {
self.progress.progress = Float(per)
}
videoInput.append(sample!)
}else{
videoInput.markAsFinished()
DispatchQueue.main.async {
videoFinished = true
self.progress.progress = 1.0
closeWriter()
}
break;
}
}
}
}
You can also display the progress of video compression.