How to convert AVCaptureStillImageOutput to UIImage and save as NSData? - ios

I am trying to send a photo with the app I am working on, I have made the app to take a photo and then when you tap on send it would send the photo you just took to send it through mail.
But I don't know how to convert the photo that is of type AVCaptureStillImageOutput to UIImage and store it in a NSData in order to use it as an attachment in addAttachmentData.
I tried to do this:
let data: NSData = UIImagePNGRepresentation(image: stillImageOutput)
I have this function
func doSomethingWithImage(image: UIImage) {
// do something here
mc.addAttachmentData(UIImageJPEGRepresentation(UIImage(named: imageAsUIIMage)!, CGFloat(1.0))!, mimeType: "image/jpeg", fileName: "backupOne.jpeg")
}
But It shows me an error, "Use of unresolved identifier 'imageAsUIIMage'
I want to get the UIImage in order to send it through an e-mail.

You can get capture an image and save it to file and convert it to UIImage using stillImageOutput.captureStillImageAsynchronouslyFromConnection()
// setup code
stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
captureSession.startRunning()
let connection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo)
stillImageOutput.captureStillImageAsynchronouslyFromConnection(connection) { (sampleBuffer, error) in
// NSData of jpeg data. Save to file and add as email attachment.
let jpegData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
dispatch_async(dispatch_get_main_queue(), {
self.doSomethingWithJPEGImageData(jpegData!)
})
}
// later on
func doSomethingWithJPEGImageData(jpegData: NSData) {
mc.addAttachmentData(jpegData, mimeType: "image/jpeg", fileName: "backupOne.jpeg")
}

Related

How to resolve the PhotoKit error "Original resource choice is only valid for an unadjusted base version"?

I try to add IPTC, TIFF and EXIF data to an PHAsset. When I apply changes with the following code snipped I got the mentioned error:
guard let ciImage = CIImage(contentsOf: input.fullSizeImageURL!, options: [.applyOrientationProperty:true]) else {
fatalError("Not able to create CIImage from input")
}
//Write the edited image as a JPEG.
do {
try CIContext().writeJPEGRepresentation(of: ciImage,
to: output.renderedContentURL,
colorSpace: outputImage.colorSpace!,
options: [kCGImageDestinationLossyCompressionQuality as CIImageRepresentationOption:1.0])
} catch let error {
fatalError("Can't apply metadata to the image: \(error).")
}
PHPhotoLibrary.shared().performChanges({
let request = PHAssetChangeRequest(for: self.asset!)
request.contentEditingOutput = output
}, completionHandler: { success, error in
if !success {
print("Can't edit the asset: \(error?.localizedDescription)")
}
}
Error:
[PhotoKit] Original resource choice is only valid for an unadjusted base version
What am I doing wrong? Is there a better way to add IPTC metadata to a PHAsset, resp. UIImage file?
If found the issue which was in the code before I created the CIImage shown in my question. I deleted the code and instead of overriding the binary data of the CIImage I just use the CIImage to store my changes in the PHAsset / PHAssetLibrary.

Converting an Image from Heic to Jpeg/Jpg

I have an application where user can upload multiple images and all the images will be stored in a server and will be displayed on a web view in my iOS application.
Now everything used to work just about fine till iOS 10 but suddenly we started seeing some pictures/ images not being displayed , after a little debugging we found out that this is the problem caused because of the new image format of apple (HEIC),
I tried changing back to the Native UIImagePicker (picks only one image) and the images are being displayed as Apple I guess is converting the Image from HEIC to JPG when a user picks them, but this is not the case when I use 3rd party libraries as I need to implement multiple image picker.
Though we are hard at work to make the conversion process on the server side to avoid users who have not updated the app to face troubles, I also want to see if there is any way in which I can convert the image format locally in my application.
There's a workaround to convert HEIC photos to JPEG before uploading them to the server :
NSData *jpgImageData = UIImageJPEGRepresentation(image, 0.7);
If you use PHAsset, the, in order to have the image object, you'll need to call this method from PHImageManager:
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
On server side you also have the ability to use this API or this website directly
I've done it this way,
let newImageSize = Utility.getJpegData(imageData: imageData!, referenceUrl: referenceUrl!)
/**
- Convert heic image to jpeg format
*/
public static func getJpegData(imageData: Data, referenceUrl: NSURL) -> Data {
var newImageSize: Data?
if (try? Data(contentsOf: referenceUrl as URL)) != nil
{
let image: UIImage = UIImage(data: imageData)!
newImageSize = image.jpegData(compressionQuality: 1.0)
}
return newImageSize!
}
In Swift 3, given an input path of an existing HEIF pic and an output path where to save the future JPG file:
func fromHeicToJpg(heicPath: String, jpgPath: String) -> UIImage? {
let heicImage = UIImage(named:heicPath)
let jpgImageData = UIImageJPEGRepresentation(heicImage!, 1.0)
FileManager.default.createFile(atPath: jpgPath, contents: jpgImageData, attributes: nil)
let jpgImage = UIImage(named: jpgPath)
return jpgImage
}
It returns the UIImage of the jpgPath or null if something went wrong.
I have found the existing answers to be helpful but I have decided to post my take on the solution to this problem as well. Hopefully it's a bit clearer and "complete".
This solution saves the image to a file.
private let fileManager: FileManager
func save(asset: PHAsset, to destination: URL) {
let options = PHContentEditingInputRequestOptions()
options.isNetworkAccessAllowed = true
asset.requestContentEditingInput(with: options) { input, info in
guard let input = input, let url = input.fullSizeImageURL else {
return // you might want to handle this case
}
do {
try self.save(input, at: url, to: destination)
// success!
} catch {
// failure, handle the error!
}
}
}
private func copy(
_ input: PHContentEditingInput, at url: URL, to destination: URL
) throws {
let uniformType = input.uniformTypeIdentifier ?? ""
switch uniformType {
case UTType.jpeg.identifier:
// Copy JPEG files directly
try fileManager.copyItem(at: url, to: destination)
default:
// Convert HEIC/PNG and other formats to JPEG and save to file
let image = UIImage(data: try Data(contentsOf: url))
guard let data = image?.jpegData(compressionQuality: 1) else {
return // you might want to handle this case
}
try data.write(to: destination)
}
}

Having trouble retrieving images from PubNub didReceiveMessage Function in Swift App

I'm writing a Swift chat app using JSQMessageViewController as well as PubNub. I have no problem getting text messages in real time and display them correctly. But I'm stuck on retrieving image messages, I can send images without any problems but when the receiver gets the image it becomes a NSCFString data. The output of print(message.data.message) in PubNub's didReceiveMessage function is :<UIImage: 0x155d52020>, {256, 342}, And the output of print(message.data) is : { message = "<UIImage: 0x155d52020>, {256, 342}"; subscribedChannel = aUpVlGKxjR; timetoken = 14497691787509050;}
Does anyone know how to convert this data to UIImage?
You need to convert UIImage to base64 encoding and then send to pubnub message and then decode base64 into UIImage.
Encode:
let imageData = UIImagePNGRepresentation(image)
let imageString = imageData.base64EncodedStringWithOptions(.allZeros)
Decode:
let imageData = NSData(base64EncodedString: imageString, options: NSDataBase64DecodingOptions.fromRaw(0)!)
var image = UIImage(data: imageData)
Reference: Convert between UIImage and Base64 string

How to decompress a jpeg with swift that was compressed with UIImageJPEGRepresentation(_) -> NSData?

I'm using UIImageJPEGRepresentation(...) to compress images before I store them on a server. My problem is when I am retrieving them from the server I need a way to decompress them in order to display the image again. How would I go about this using swift?
Thanks!
It's as simple as creating a UIImage from the NSData representing the image
//imageData is the JPEG compressed data retrieved from your server
if let image = UIImage(data: imageData) {
//do something with image
} else {
//image is nil, do something else
}
you might be use below code:
let img = UIImage(data: serverData) // serverdata means get response to server side

Unable to edit screenshots, performChanges block fails

I'm developing an app that allows users to edit photos using PhotoKit. I was previously saving the edited photo to disk as a JPEG. I would like to avoid converting to JPEG and have implemented the modifications in order to do that. It works great for photos taken with the camera, but if you try to edit a screenshot, the PHPhotoLibrary.sharedPhotoLibrary().performChanges block will fail and log The operation couldn’t be completed. (Cocoa error -1.). I am not sure why this is causing the performChanges block to fail, what have I done wrong here?
I've created a sample app available to download that demonstrates the problem, and I've included the relevant code below. The app attempts to edit the newest photo in your photo library. If it succeeds it will prompt for access to edit the photo, otherwise nothing will happen and you'll see the console log. To reproduce the issue, take a screenshot then run the app.
Current code that works with screenshots:
let jpegData: NSData = outputPhoto.jpegRepresentationWithCompressionQuality(0.9)
let contentEditingOutput = PHContentEditingOutput(contentEditingInput: self.input)
var error: NSError?
let success = jpegData.writeToURL(contentEditingOutput.renderedContentURL, options: NSDataWritingOptions.AtomicWrite, error: &error)
if success {
return contentEditingOutput
} else {
return nil
}
Replacement code that causes screenshots to fail:
let url = self.input.fullSizeImageURL
let orientation = self.input.fullSizeImageOrientation
var inputImage = CIImage(contentsOfURL: url)
inputImage = inputImage.imageByApplyingOrientation(orientation)
let outputPhoto = createOutputImageFromInputImage(inputImage)!
let originalImageData = NSData(contentsOfURL: self.input.fullSizeImageURL)!
let imageSource = CGImageSourceCreateWithData(originalImageData, nil)
let dataRef = CFDataCreateMutable(nil, 0)
let destination = CGImageDestinationCreateWithData(dataRef, CGImageSourceGetType(imageSource), 1, nil) //getType automatically selects JPG, PNG, etc based on original format
struct ContextStruct {
static var ciContext: CIContext? = nil
}
if ContextStruct.ciContext == nil {
let eaglContext = EAGLContext(API: .OpenGLES2)
ContextStruct.ciContext = CIContext(EAGLContext: eaglContext)
}
let cgImage = ContextStruct.ciContext!.createCGImage(outputPhoto, fromRect: outputPhoto.extent())
CGImageDestinationAddImage(destination, cgImage, nil)
if CGImageDestinationFinalize(destination) {
let contentEditingOutput = PHContentEditingOutput(contentEditingInput: self.input)
var error: NSError?
let imageData: NSData = dataRef
let success = imageData.writeToURL(contentEditingOutput.renderedContentURL, options: .AtomicWrite, error: &error)
if success {
//it does succeed
return contentEditingOutput
} else {
return nil
}
}
The problem happens due to the fact that adjusted photos are always saved as JPG files, and screenshots are in fact PNG files.
It occurred to me while I was debugging your sample project and saw the in the PhotoEditor, contentEditingOutput.renderedContentURL is a URL to a JPG, while if you examine the result of CGImageSourceGetType(imageSource) it is clear the it's a PNG (returns a PNG UTI: public.png).
So I went and read the documentation for renderedContentURL which states that if editing a photo asset, the altered image is written in JPEG format - which clearly won't work if your image is a PNG. This leads me to think that Apple don't support editing PNG files or don't want you to. Go figure..

Resources