Contacts module: Access profile picture
Is there a way to use the
contactsmodule to get and edit profile pictures for iOS contacts?
I'm sure I'd be able to do that with
objc_util, but before I'd like to try if it can be done using the built in
I'm not sure you'd be able to with objc_util. I don't know if apps are allowed to have this kind of write access to contacts.
contactsmodule currently doesn't expose that functionality (still on my todo list).
It's definitely possible to do this with
ctypes, but I don't think it would be possible to mix and match this approach with the
contactsmodule. You can't get at the pointers to the underlying data structures in
contacts, so if you want to edit a profile picture of a person using
objc_util, you also have to find the right person object using that, and can't use the simpler
I'll see if I can come up with an example, not completely sure how much code is required right now.
Okay, here's some sample code that shows how to use
objc_utilwith the Contacts framework to:
- Find a person by name
- Access its picture, and convert it to a
ui.Imageto show it in the console
- Set a new picture (picked from photos here, but you could of course also get this elsewhere)
- Save the changes
Before you run the example, set the
CONTACT_NAMEvariable (near the top) to a name of someone in your contacts (or create a contact named "John Doe").
from objc_util import * from ctypes import string_at import contacts import ui import photos # CHANGE THIS: CONTACT_NAME = 'John Doe' # Easier to do the authorization with the contacts module (this also authorizes the Contacts.framework): if not contacts.is_authorized(): # This implicitly shows the permission dialog, if necessary: contacts.get_all_groups() # Load classes we need from Contacts.framework: NSBundle.bundleWithPath_('/System/Library/Frameworks/Contacts.framework').load() CNContactStore = ObjCClass('CNContactStore') CNContact = ObjCClass('CNContact') CNSaveRequest = ObjCClass('CNSaveRequest') def main(): store = CNContactStore.alloc().init().autorelease() # Find the first contact that matches the name. pred = CNContact.predicateForContactsMatchingName_(CONTACT_NAME) fetch_keys = ['imageDataAvailable', 'imageData'] people = store.unifiedContactsMatchingPredicate_keysToFetch_error_(pred, fetch_keys, None) if not people: print 'No person found with the name "%s"' % (CONTACT_NAME,) return p = people has_image = p.imageDataAvailable() if has_image: # Show the existing picture of the contact: img_data = p.imageData() img_data_str = string_at(img_data.bytes(), img_data.length()) img = ui.Image.from_data(img_data_str) img.show() # Pick a new image from photos: new_img_data = photos.pick_image(raw_data=True) if new_img_data: # Note: objc_util automatically converts bytearray to NSData new_img_bytes = bytearray(new_img_data) # Create a mutable copy of the fetched contact... mutable_contact = p.mutableCopy().autorelease() # Assign new image data... mutable_contact.imageData = new_img_bytes # Create a save request for he contact, and execute it... save_req = CNSaveRequest.new().autorelease() save_req.updateContact_(mutable_contact) store.executeSaveRequest_error_(save_req, None) if __name__ == '__main__': main()
Thank you @omz, the code you shared is working perfectly