I'm trying to implement a little tool to manipulate photos on the iPhone. I'm currently using both the simulator and an iPhone 7 with iOS 13.5.1.
I've noticed that when I copy a photo from the Mac to the simulator or via iCloud to the device, the dimensions after picking it in my app differ a lot from what the macOS Photos app tells me they should be.
Example:
Panorama in macOS Photos with dimensions of 14204 × 3628 pixels is exported as original version. Finder shows the same dimensions.
Image file copied to simulator via drag & drop and opened by my app with UIImagePickerController: 2048 x 523 pixels.
Panorama copied to device via iCloud and opened by my app with UIImagePickerController: 4096 x 1046
I'd actually like to open the image with its real dimensions as shown in Finder and Photos. I'm currently using the following code:
#IBAction func btnAddProjectPressed(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true, completion: { () -> Void in
})
pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
imageView.image = image
}
UPDATE:
I've managed to get the unscaled image using the .phAsset value from the info dictionary, loading the "real" image using the PHImageManager. However, this outputs the message
Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)"
This problem is described in many questions here (for example this one) and I could not really find a solution. Even Apple's sample project outputs this error and doesn't show any photos or albums.
However, combining the UIImagePickerController and the PHImageManager seems to reduce this to a warning so that I do get the full-sized image.
Related
I need to get the metaData from an Image I'm picking via UIImagePickerController.
This is my code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let metaData = info[UIImagePickerController.InfoKey.mediaMetadata] as? [AnyHashable: Any]
print(metaData)
picker.dismiss(animated: true, completion: nil)
}
It works fine, when im picking the Image having .camera as source. But when I use .photoLibrary as source, then metaData is nil. I already read through other questions and tried stuff like
let asset = info[.phAsset] as? PHAsset
print(asset?.creationDate ?? "None")
print(asset?.location ?? "None")
But this also returns nil. I guess the source of the problem is, that the info-Dictionary only returns 4 Keys when picking from .photoLibrary:
UIImagePickerControllerOriginalImage
UIImagePickerControllerMediaType
UIImagePickerControllerImageURL
UIImagePickerControllerReferenceURL
It would be awesome if someone could tell me where my mistake is.
Thanks in advance !
I had the same problem. If the user does not grant access to the photo library first, info[.phAsset] will return nil.
Quote from Apple: "Accessing the photo library always requires explicit permission from the user. The first time your app uses PHAsset, PHCollection, PHAssetCollection, or PHCollectionList methods to fetch content from the library ..."
Thus, you have to call PHPhotoLibrary.requestAuthorization{ ... } before presenting the image picker.
If the user denies the request, info[.phAsset] will also be nil!
This key is valid only when using an image picker whose source type is set to UIImagePickerController.SourceType.camera, and applies only to still images.
The value for this key is an NSDictionary object that contains the metadata of the photo that was just captured. To store the metadata along with the image in the Camera Roll, use the PHAssetChangeRequest class from the Photos framework.
https://developer.apple.com/documentation/uikit/uiimagepickercontroller/infokey/1619147-mediametadata
I am using this ImagePicker to select multiple images from library or camera. Once user is done selecting images, I am storing those images in to an array. I want display images to the Frame according to number of images selected. for example, if more than 5 images selected the result will be something like this from the selected Images.
Imagepicker is new for me. I don't know how to achieve this. I've read many posts but not getting clear idea how to implement in my case.
I am testing it on Demo project given,
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
imagePicker.dismiss(animated: true, completion: nil)
imageArray = images
createCollage()
}
func createCollage() {
}
If I use UIimageView to display/load images it shows massive memory usage.
Can please anyone help me here with any of these issue? Any help will be much appreciated!!
look at the doc and code of ImagePicker, they are recommend to use
public var imageAssets: [UIImage] {
return AssetManager.resolveAssets(imagePicker.stack.assets)
}
by looking for AssetManager.resolveAssets implementation we will se some config size
open static func resolveAsset(_ asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280), completion: #escaping (_ image: UIImage?) -> Void) {
set size depends from your imageView size
--- UPD
or use the property
open var preferredImageSize: CGSize?
Tested the same code on real device and it is working fine. In my case, testing on simulator was causing massive memory usage issue here.
I'm trying to obtain a video from the library in my swift app.
I'm using the following code snippet :
print("ChatDetailsController - imgaction - Vid from Lib pressed")
self.selection = "videoLib";
self.imgSelection = "vidFromLib"
self.imagePicker.sourceType = .PhotoLibrary
self.imagePicker.delegate = self
self.imagePicker.mediaTypes = ["public.movie"]
self.presentViewController(self.imagePicker!, animated: true, completion: nil)
Then in delegate method:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
if(selection == "videoLib")
{
if let videoURL = info[UIImagePickerControllerReferenceURL] as? NSURL
{
print("imagePickerController - reached for video - from Lib - \(videoURL)")
let videoData = NSData(contentsOfURL: videoURL)
}
}
}
When running the app, it shows the library and I can select a video, then it says compressing video.. but then the app crashes.
The Crash happens when I try to access the videoData Variable becuase it wasn't able to get the actual data since the path is an asset path and not a video path.
The Log shows something similar to this:
fatal error: unexpectedly found nil while unwrapping an Optional value
The print function shows:
imagePickerController - reached for video - from Lib - assets-library://asset/asset.MOV?id=7D3BFA00-A7CB-470C-8899-F82FCC2CBC54&ext=MOV
Also, right after choosing/selecting the video, a message similar to this is displayed in the console/log:
[Generic] video path /var/mobile/Media/PhotoData/CPLAssets/group419/A2901DD1-FDEF-423B-B4A3-E808B9AC45E1.MOV for PLPreviewImageAndDurationForVideoAtPath does not exist
Of course the file name changes on every run.
I'm able to get a video and images from the camera, and getting images from the library, I'm only having trouble with using the the video from the library. I would expect to see the video URL similar to :
/var/mobile/Containers/Data/Application/BEDDC883-B20E-496D-8C9A-A40EC0A29214/Documents/63ea24932c101b76c72fcbae3993fc9b.mov for example; where the video file is in the application and not showing as an unusable asset URL.
Any help would be appreciated.
The problem is that you're trying to fetch the wrong video. You're trying to use info[UIImagePickerControllerReferenceURL]. What you want is info[UIImagePickerControllerMediaURL].
Background
I recently asked this question: convert NSData of an image into a string
But, I have run into an odd problem: my code tells me that all images are .png files.
For instance this image which I downloaded onto my iphone simulator and uploaded to my app as an NSData object:
<89504e47 0d0a1a0a 0000000d 49484452 00000032 00000032 08060000 001e3f88 b1000000 01735247 4200aece 1ce90000 001c6944 4f540000 00020000 00000000 00190000 00280000 00190000 00190000 01585cd2 43eb0000 01244944 41546805 ec93d10d c3200c44 bb5c36ed 089da36b 545da0bf 691eea45 861a1148 3e12c948 08e3e0e3 9e696fb7 18d181e8 4074203a 101db870 07e6df00 c1c69742 c2f8344d 6996f125 a0641288 f7e79e66 195bc043 5f87cbf5 fc7b84d1 914999b7 7bc51650 77efb937 d522343f 5e69d13a 228a80cc 6354a69f 4b5c4e7d d34aedc8 9d6b0d02 c93c2076 760a2323 538228cd 7b7b6a74 1e8dd558 6f407106 20980e51 24ac2162 cf742da7 06a0d3eb 3f3b8f40 06d32948 b940d4dd 9a692f7f 18085498 4930cb92 516ed850 2a1056cf 6c2b471d 63c375ed 237b84a8 55675ba6 bdef8782 b451fd13 8218f959 092a40fc de8e67f5 2a74565d deb2ea7c bcc878ef ff2bf51a b5ff88ba 5e7ba153 bc065880 3030644d dbb80641 fe142016 c0334ece cb0b6c2b c4170000 ffffa32a b1ee0000 012b4944 4154ed95 d10dc230 0c44bb5c 37651ef6 60017e81 abfaa493 95b46e15 d27ec452 b01b5fe2 3b1bca34 35b4cf6a ba92789e e7cfebfd 5896e2e7 2ff6a53d 997c6929 d790e2fe 554ec663 91931079 1740acfd 2ddbafdc 08010908 43daa750 13213108 6944e7dc 35b5ce8b 1c8bce6f f94bc520 22dbf95b 0a41045d 97df22ba 97bb6422 88e0b7b0 473293ef 2e04114c 22433283 e92a0411 2d272191 5d45e89d 861015ce 74398be9 2a0411ad a7d17d22 0889d388 cfd92980 bb641a2a 5a225edb 03ef1e01 78e564e7 fe8e0f9c 62125b5f a92804e2 0bc3f503 0cfe3221 91801389 393d6bc9 fc25a133 8e75cc81 de9e838a 8c178f02 4a79e19d a463fc2e c79c6377 f0144420 0801edeb aa5adecb 64308eff 5b2c226e b190e714 c7bc9e33 98d2b9b1 373a303a 303a303a 70eb0e7c 01f5b991 16aea4e6 27000000 0049454e 44ae4260 82>
which I got from here: http://www.picgifs.com/graphics/k/kawaii-small/graphics-kawaii-small-042264.gif is a tiny .gif file.
But has all the magic numbers of a .png file so my code:
if image.length >= pngHeader.count {
if memcmp(image.bytes, pngHeader, pngHeader.count) == 0 {
image_type = "png"
}
}
will always mislabel the image.
Question:
Is there a more reliable way to determine image type?
Does xcode convert image types upon upload? Do iphones do this?
Extra info:
The user select the image from their phone by clicking a button that allows them to select the image that they would like to upload from their phone.
The code to upload from phone to app is this:
#IBOutlet var image: UIImageView!
#IBAction func loadImage(sender: AnyObject) {
let ImagePicker = UIImagePickerController()
ImagePicker.delegate = self
ImagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
self.presentViewController(ImagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
image.image = info[UIImagePickerControllerOriginalImage] as? UIImage
self.dismissViewControllerAnimated(true, completion: nil)
}
Currently I am using this code:
#IBAction func selectPicture(sender: UIButton) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary){
var imag = UIImagePickerController()
imag.delegate = self
imag.sourceType = .Camera;
imag.mediaTypes = [kUTTypeImage as String]
imag.allowsEditing = false
imag.modalPresentationStyle = .Popover
self.presentViewController(imag, animated: true, completion: nil)
}
}
But when I run it on the iPad of iPhone device it asks me only for the camera permission and I don't have the possibility to choose a photo from any album/camera roll.
What can I do so I can access the photos from the device ?
You are setting the wrong sourceType:
imag.sourceType = .Camera;
Change that to:
imag.sourceType = .SavedPhotosAlbum;
or
imag.sourceType = .PhotoLibrary
The constants are defined in UIImagePickerControllerSourceType Enumeration and the definition is like:
UIImagePickerControllerSourceType
The source to use when picking an image or when determining available
media types. Declaration
Swift
enum UIImagePickerControllerSourceType : Int
{
case PhotoLibrary
case Camera
case SavedPhotosAlbum
}
Constants
PhotoLibrary
Specifies the device’s photo library as the source for the image picker controller.
Camera
Specifies the device’s built-in camera as the source for the image picker controller. Indicate the specific camera you want (front or
rear, as available) by using the cameraDevice property.
SavedPhotosAlbum
Specifies the device’s Camera Roll album as the source for the image picker controller. If the device does not have a camera,
specifies the Saved Photos album as the source.
Discussion
A given source may not be available on a given device because the
source is not physically present or because it cannot currently be
accessed.