简体   繁体   English

Python / Django-Vcard照片

[英]Python / Django - Vcard Photo

I'm trying to generate a vcard using the vobject library but I am running into a couple of issues. 我正在尝试使用vobject库生成vcard,但遇到了两个问题。

First off, I've tried adding a photo using both a url and base64 data, but I cannot get the photo to display on the OS X contacts app (Mavericks), or a Galaxy S4 running Android 4.4.2 . 首先,我尝试使用url和base64数据添加照片,但无法在OS X联系人应用程序(Mavericks)或运行Android 4.4.2的Galaxy S4上显示照片。 I even tried this on my Lumia 1520 running windows phone 8.1, but to no avail. 我什至在运行Windows Phone 8.1的Lumia 1520上尝试了此操作,但无济于事。

The code is as follows: 代码如下:

card = vobject.vCard()

attr = card.add('n')
attr.value = vobject.vcard.Name(family=agent.last_name, given=agent.first_name)

attr = card.add('fn')
attr.value = agent.get_full_name()

attr = card.add('email')
attr.value = agent.email_address
attr.type_param = 'INTERNET'

attr = card.add('tel')
attr.value = agent.cell_number
attr.type_param = 'cell'

attr = card.add('tel')
attr.value = branch.get_telephone_number()
attr.type_param = 'work'

attr = card.add('org')
attr.value = "Moe's Co"

photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()

attr = card.add('photo')
attr.type_param = 'JPEG'
attr.value = photo_url

response = HttpResponse(mimetype='text/x-vcard')
response['Content-Disposition'] = 'attachment; filename="%s.vcf"' % agent.get_full_name()
response.write(card.serialize())

return response

This generates the following file: 这将生成以下文件:

BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:test@example.com
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=JPEG:http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD

The above method places the URL of the image as the photo. 上面的方法将图像的URL放置为照片。 The code for the base 64 implementation (see here for more info) is shown below: 基本64实现的代码(请参见此处以获取更多信息)如下所示:

photo_url = "http://www.abcrealestate.co.za/resize/100/150/uploads/agents/2012/03/testagent.jpg"
f = urllib.urlopen(photo_url)
data = f.read()
f.close()

attr = vcard.add('photo')
attr.type_param = 'jpeg'
attr.encoding_param = 'b'
attr.value = base64.encodestring(data)

The result: 结果:

BEGIN:VCARD
VERSION:3.0
EMAIL;TYPE=INTERNET:test@example.com
FN:Abad Muhammed
N:Muhammed;Abad
ORG:M;o;e;';s; ;C;o
PHOTO;TYPE=jpeg;ENCODING=b:LzlqLzRBQVFTa1pKUmdBQkFRQUFBUUFCQUFELzJ3QkRBQU1DQWdNQ0FnTURBd01FQXdNRUJRZ0ZCUVFFQlFvSEJ3WUlEQW9NREFzSwpDd3NORGhJUURRNFJEZ3NMRUJZUUVSTVVGUlVWREE4WEdCWVVHQklVRlJULzJ3QkRBUU1FQkFVRUJRa0ZCUWtVRFFzTkZCUVVGQlFVCkZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJUL3dBQVJDQUNXQUdRREFTSUEKQWhFQkF4RUIvOFFBSHdBQUFRVUJBUUVCQVFFQUFBQUFBQUFBQUFFQ0F3UUZCZ2NJQ1FvTC84UUF0UkFBQWdFREF3SUVBd1VGQkFRQQpBQUY5QVFJREFBUVJCUkloTVVFR0UxRmhCeUp4RkRLQmthRUlJMEt4d1JWUzBmQWtNMkp5Z2drS0ZoY1lHUm9sSmljb0tTbzBOVFkzCk9EazZRMFJGUmtkSVNVcFRWRlZXVjFoWldtTmtaV1puYUdscWMzUjFkbmQ0ZVhxRGhJV0doNGlKaXBLVGxKV1dsNWlabXFLanBLV20KcDZpcHFyS3p0TFcydDdpNXVzTER4TVhHeDhqSnl0TFQxTlhXMTlqWjJ1SGk0K1RsNXVmbzZlcng4dlAwOWZiMytQbjYvOFFBSHdFQQpBd0VCQVFFQkFRRUJBUUFBQUFBQUFBRUNBd1FGQmdjSUNRb0wvOFFBdFJFQUFnRUNCQVFEQkFjRkJBUUFBUUozQUFFQ0F4RUVCU0V4CkJoSkJVUWRoY1JNaU1vRUlGRUtSb2JIQkNTTXpVdkFWWW5MUkNoWWtOT0VsOFJjWUdSb21KeWdwS2pVMk56ZzVPa05FUlVaSFNFbEsKVTFSVlZsZFlXVnBqWkdWbVoyaHBhbk4wZFhaM2VIbDZnb09FaFlhSGlJbUtrcE9VbFphWG1KbWFvcU9rcGFhbnFLbXFzck8wdGJhMwp1TG02d3NQRXhjYkh5TW5LMHRQVTFkYlgyTm5hNHVQazVlYm42T25xOHZQMDlmYjMrUG42LzlvQURBTUJBQUlSQXhFQVB3RDlVNktLCktBQ2lpaWdBb29vb0FLS0thN2hGSlBTZ0NscWVxMnVpMkU5N2V6cGJXc0s3NUpwRGhWWDFyNXUrSW43Ym1qZUVneDA3dy9xMTdiSzIKMXRRdUxkb1lWLzJ0djMyWDhLNWY5b2Y0NVJhOVBQb3R1WWY3RWdrMnFWdUZXVzZrWCtKVi91ci9BQTE4amVLdkRYanJ4QTAxMXBxeQp5MmJmSzBlcGJmM2kvd0M4dTFxK1F4bWEvdlBaMHBXUjlYZ2NubFZoN1NwRSszZkJYN1oxbHJWeTBPcFd0dWpLcXliWTVOdjd0djhBCmxvck44ckwvQU44MTlDZUV2R0dsZU05TkY3cFZ5bHhGOTFnUHZJMzkxcS9HcXgwbnhsNFhhMWt2OU5sbGtzMXVMZUh5bTNOSkRNdisKcjNmM1ZiNXE5dCtDbjdTSGlUNFhhL2VGTk44K084a3Qxa2p1MlpZMlZWMnQ4MzhMZjNhTUxtVTR5NWFrdWFJOFpsWHU4MFljc2o5Ugp0dEZlUmVDZjJtL0JmaVhRWXIyOTFHRFFMb3NVa3N0UWxWWkZJNys0OUQzb3I2Tll1aS90SHpMdzlSYWNwNi9SUlJYWVloUlJSUUFVClVVVUFKMnhYbjN4eDhWbndYOE10YjFKRHRrRVloVnY3clNNSTkzL2oxZWduaXZNLzJpdkM5MTR5K0RIaXJUTE9Qekx5UzA4MkpDZnYKTkd5eUFmOEFqdGM5ZE9WS1hLYlVPWDJzZVk4RzhFL0NqVExTeHRieTVqYTZta1ZadDA3ZVp0WnZtYXVsMXpTTlBhejhsTGVOZHY4QQpzMWphVjR4azhJL0QzUjlRMVM3MHZUbS9zMk9abDFTU1RjMjJOZk1iYXRiMFhqblJkZDhGcjRoRXRxTGRsMnM4Yk50WnYrQmZOWDV5CjhMSGt1ZnA5TEVTNW94UEdQRjJoMnIzRExGdDNWNUw0ODA1YlBUWkxqeTFsamorV1JXL2lWcTlNOFFlTDRkWm04eGI3UWRQaG0zZloKZnRNMGl5WEczNzIzNWR2eTE1LzhTb3ByRHdmcWtseEdxK1hIdWJhMjVXWCs4clZ3VThQVW9WSTh4NjFXdEN0VGxGSExlSGZHK2sydQptSkhNdC9jT0Nja3RuYjdVVjRMYitLNzFwTGsyeXQ1Um1iSHkwVjczMVUrUDlvZnZwUlJSWDM1OElGRkZGQUJSUlJRQW1PS3p0ZWpWCjlIdmxmN3BnZmRqL0FIYTBxWTZCMEtrY1ZFbzNqWWNYeXl1ZUJhbm85dDloOHFXTzFXMlpmSi9mUjd0cS93QjFhODcrS0hoeExQd0sKZFB0YlRiYlNTZEZYNzFlZ2VQTEc4MHk2dTd1M3NKZFRldzgxb2JDR1JZMmtiK0hidStYZHQrN3VyenZ4cUwzeFA0ZFdWRnNZN2J5LwpNbWphL1dPYUZ2bCtWbGJiODFmQU9FcWlsSGwrRS9WY0ZKUGxtcEhtbmh2d2xEcTNodGJON1cydkxleDNSckJPdnpRN20rWmR2OE5ZCnZpVHd1dC9vdDFwYktxd3RENWFyL0N2L0FOalcxOE85U211dkVHcVc5cmEzTVZyWjIvbVhGOHpLMXRKdS93Q1dhdC9FeTBXcWZiOVMKdlBOL2VxdHF6TXYrMS9Ddi9mVmVXK2FWU05OL0VldlY1YWNaTkhnZGpvemVEMGxzSWRJRjFENWpPczdXVEV5WjRMWjc4ZzBWOXNmcwpqL0NQVWIvNFZUWGZqSFRiU2EvdU5WdW50V3VMV01uN0tDRmp4N2ZLMktLOXhZQ3M5ZVkrZi90bkF3OTNrMlByZWlpaXZ1ajh5Q2lpCmlnQW9vb29BS0tLS0FQT3ZpSGF4Mk43YjN3R3d6aG9wVDlQdXRYa0hqKzBzbXRacHJxd3Q1UTN5dDgzM3E5ZCtLdXQyTnJjYU5wTXoKcUwyOWVhU0dQKzhzY2Z6ZitoTFhoM2pmNGVXZXBMRzFwZFh6WEZ4OTIyaWszZk5YeEdZWGhYbjdNKzh5YXE2ZEdNcEhqWGlMeHZZKwpITEc0dDdObGlhVDkzdFgrN1QvZ0g1dmo3eDVwMXUwTHJveTNNYzEvZHQ5MWxWdHl4LzhBQW0yN3E3WFRmMlhiTkcrM2VJN2hwZjR2CnNrYmJWWC9lYXZFLzJwdjJzOUwrQlduemVBL2h1dHN2aVpvOXR4ZHdLclI2V3JmK2hUZitnL2VhcXkvS2FrcFJyVmZkRE1zNXB1TXEKTkxXWDRINmxSdytUR2tjUVNORkdBb0hTaXZ5SStBUC9BQVZJOFFmQ3I0YVdIaGp4RDRmdVBHVnhZdTZXK3BTM3pwTjVKd1ZqbEpCMwpzcExmTi9kMmp0UlgyVmo0TS9YNmlpaXJBS0tLS0FDaWl2UGZpSjhlZmg5OEtMbUsyOFdlTHRMMFc4bFhlbG5QTnVtWmY3M2xybHR2CisxdG9BOUNyejc0cmZIWHdIOEVORy90SHhwNGtzOURoWmN4d3l2dW5sLzY1d3JtUi93RGdLMThEZnRNZjhGU3IrNGl1dEUrRmxwSnAKa0xiby93RGhJTCtQZGNTRC9wakQ5MlAvQUhtM04vc3JYd2hkZUpkYThVYXRlYTU0aHZMbld0V3VOMGpYZW9UTk5NemY3VE5VQWZxago4WWZFSStPSHhxK0ZzL2dUVnhGZmFIL3hNdFdzN3VHUlpMZXh1TFZtVnBGL3ZmZFhidStWcEYzYmE5OWgreTZYR3F3UnJGY05Hdm1UCi93QVRmN3JmM2ErY2ZnL2NMTDhmSWZGVnJHdjlrNnA0VGh1SkdXUGR0YVJZMmpWZjlyNzFlamZIVDR0YWI4S1BBTjk0MjFlR1NLeHMKMWFPM2czZnZMcWIvQUpaeHIvdk4vd0N6ZjNheGhocWJxU3E4dnZIWlBFMUhUalNVdmRQQy93QnZEOXFKdmhQNFpid3o0ZnV2SzhXYQpsR3F3dEg4eldzUDhVMys5L0N2KzF1YitHdnkxdVBNZHByeSttYWU0bWtacEdsYmN6TTMzbVpxNnJ4eDR3MXI0b2VOTlU4WGVJSnZQCjFUVXBtbVpWKzdHdjhNYS83S3I4cTFodzJ2MnE0V1psWHk0L3VzMzhUZjNxN0RqSUxiVG96Q3BmY1dORmF2bE5SUUIvU0xSUlJVQUYKRkZGQUhHZkZ2NGxhWDhIdmgzcmZqRFd2TmZUOUxoOHhvNFYzUEl4WUtpTC9BTHpNcTErRGZqVDRoNnQ4UlBHWGlMeFpyTncwK3FheApmU1RUU00zM1YzZktxLzdLL2RWZjdxMStoSC9CVHI5b3E0c0dzL2hWb2Q1NWZuUnJlYTk1ZjhVYmY2bTNiLzBZMy9iT3Z6QjFDOVd3CnM1R2IrRnBQL1FxamxBZGZOOW84UVJ4L3c3dk1yVzMvQUhWck5odDltcGVZMy9QUGJWeGJqWXpTTjkxZm1xK1VEOWJQMkE5TTFEVy8KMlovRE45cUxMY3pOY1hrTnJLMGZ6UjJjTXpSd3gvN1g4VzJ2ajcvZ294OGNCOFR2aXZINEgwZTQzZUZmQ0ROYnNJMitXZSsvNWJTZgo4Qi8xYS83cmYzcStzOUkrSmtmN012OEF3VHc4SjYxR3l4NnkzaCszaDAxRy9pdnJwV2tWditBN21rLzREWDVQelhFaitaTTdOUGRUCk16YnBHK2FSbSs4emYraFZZRk82VDdSSjlsVCs3KytiKzZ2OTMvZ1ZXRjJvdjkxZnVyVWNLYlY4dFczTXpicEpmN3pWUisyTGM2MU4KQ1A4QVUyc2FyLzIwYi83R3FBdE5ja241UHUwVWprQnVldEZBSDlKVkZGRlpBRll2aTN4UnAvZ3J3MXF1dmF2UDlsMHpUTGFTOHVwcwpaMnh4cnVhdHF2anIvZ3AzOFYwOEMvczVYUGg4TEtMenhWT3RoSE5IS0Y4bU5HV1NSbVg3eksyMVkvbC81NmZlb0EvTG40MmZFbTQrCkp2eE84U2VLcnhuV2JWcjZTNlZXL3dDV2NiTis3ai80REdxci93QUJyeUh4WmRMY1c5cnNiNzF3cXRXOWZYdjJoZm0rV1QrSmE0M3gKRlA4QTZQd3UzeTdoVy84QUhhc0R2cnB0alZSdkoyWFQ3eHY3c0xmK2cxWXZwZjNLeWYzbXJZK0Z1azJ2aWo0a2VHOUwxRnR1bXpYMApjbDgzOTIxai9mVGYrUTQ1S29ENlcvYnErSmJYODN3OStHTnZKNVduK0Q5QnMydkYzZjhBTDVKYXgvSzMvWE9OVi83K05YeW5KdWxYCnpQOEFWYmwycXJmd3JXMTQ4OFpYWHhFOGJhOTRtdmYrUGpXTDZiVUpsYitGWkpHWlkvOEFnUHlyL3VyWE56VHMrNXQxQUVjbDU5bFcKUmxWZmxXc1R3azhzdzFHOE9OczB2RGZ4VlBxQ3pYRUxSd0swczBueXF0VDZaWS8ySnBpVzd5TDVtNW1rWmY3MUFFenNkM0xVVlRlUwpNdDk5RFJWZ2YweVVVVVZ6Z1kzaW54UnBmZ3J3M3FXdmF6ZHg2ZnBPbXdTWFYxY3ljTEhHbzNNMWZqRjhWdmlMcXY3Yy93QzByWjJTCjZoQm9PbTN6U2FicE1kOXVhTzF0MVZtWGNxL2VrazI3bS8ybTIvdzE5Sy84RlN2Mm43ZTN0WXZoRDRldTJudW04dTg4UU5iTnU4dGYKdlEycmY3VGZMSXkvM2ZML0FMMWZudjhBQ09LenYvaTE0Wi90ZldydnducHYyeFpwdGJnaithMVpWM0xJck44djNsVmYrQlZFdmhOYQpLaktwR01qN08rSS83UHZnRWFwNEw4VHA0SHRsMGZ3M0l0bjRtMHV5M0xIY1JySHRhUmxYNXBHVnRzMzk1bDNWOGhmdGFmQStMNFk2Ci93RDJwb051emVEdFkyeldNcXllWXNmOFNydS91c3JmTFgzemZmRi93YkZwUDJyVC9FV21UcnFFZjJYVU50d3NpK1p1K1c0LzNkemYKOTh0L3MxOC9lT3J6U2Izd0g0bCtIMnU2NVlwQmEvNlpvc3ZtTElza01uemVTckx1L3dCWEo4eS83TEwvQUhhK1pvNHF2Q3I3K3g5OQppc0ZoS3RCOG5MSHpQa1pyenovRGxyTi9zeDFzZkRtNmExdC9GV3JLMjM3UHBiV01iZjNaTHFSWWYvUmYyaXVlc2RFdjQ5RG5zR1NNCk9yTXNaOHhmbSthdm83NFZmc2RlTy9GSHdoZTN0L3NHbVgydFhkdnFoKzNUTnUreHJESXNMTXFxMjNkNWtqS3JmZVhhMzNXV3ZxS3QKV25SajdTcExsaWZBd3BUcXk5blRqek0rZHRRdjlza2NLZkxKY2Z2Ry93QjMrSC94Mm9kVXY0N0NGVjNmTlgxWGUvOEFCT3p4SzJycApkUytMZE9VcXZLcFp6Ti83TXRZdmpIOWlmVGZBV2c2ajRpOFplTGI2NnNiVlYvMGJSOVBWWkpHWnRxcnVrWnR2ek45N2JYbkxOTUhLClhMR1Y1Zk05TCt5Y1hHUE5LUHUrcVBtN1E3eFpkMXh0WmwrN3VYK0dyRjFjUjd0ejBsM2FRNlVqUVdFYnhXNVptK1krWTMvQW1xZ3IKeHY4QU16SzFldWVRT2E4WFB5cTJLS2dlZDkzeXEyS0tzRCtuQ3VOK0xueERzZmhOOE12RXZqSFVCdXROR3NaYnhrSC9BQzBaVitWZgorQk50WC9nVmRsWGduN2RYaGU3OFcvc2xmRXl4c2QvMmlQUy90bTJQK0pZSkZtWmYrK1kycm5BL0RYWFBFZDU0ajhSYWhyV28zRWx6CnFWOWNTWFZ4T3pibWtta2JkSXpmN1RNMVZadFVrVmY3ek4vRC9lckprdWxWV2JkOHRReDM3UmZNcXEwemZkLzJhMUExR0xiVzgxbGEKNGtYL0FJREd0VFd0MTluaFdHTDVZVi9oL3ZWaHgzVFB1K2JlMzhUZjNxc1EzUzdmdkx1cFdRN3M5ci9aaitHY2Z4dCtPUGhYd25jZgo4Z3U0dUd1dFJaZitmT0ZmTW0vNzZWZHYvQXEvUXY0SitJWlBFdmcvVVBGRjE1Y0UydGFoY2FoNUMvZGpqWnRzTWEvM1ZXRlkxWC9kCnI0Ni80SjRlTWZEL0FJQytMK3BlSVBFT29XZGpicnBzbW54L2FabGozZWF5N3R1Ny9aajIvd0RBcTVuNG5mR0RXdmhIZDZwNEMwSHgKQnArczIwYzBqV04zYlNlWkg5bFptOHZ6R1g1VmsyL0t5MTRXYVlhdGlveGpUUGZ5bkUwTU5LY3FwK2d1cGVJSVpXVm9HYVZXKzd0Kwphdmp2OXJEOXBQVDViVzY4RjZIYjZmck1kMURKRHF6U1NTSzF1Mjc1VmpaZmwzSzN6ZnhmZDIxODNQOEF0QmZFT1d6azBtNDE2U0NHCmFML1dXMzd0djlwZHkvdzE1eGVYRTNtTXpTYldiK0pmdXRYUGc4bjluVTlwVk9ySFp4N1NuN09nTnV0THQvTWE0dFZhS1RkOTNjeTEKSHFFdXhvMmpadDIzNWxhbS9OdC85bHFuY2RLK3BQbFJmdFVuL1BScUtvbDZLeTVnUDZrcW82bHA5dHFtbjNkamRRclBhWEVaaG5oYgo3cnhzTnJLZndvb3FBUDUxdjJpL2h2RjhIL2poNHk4RTI5eDlwczlGMU9XQzNrSSs5RnkwZTcvYThzaFc5eFhtMGtoMk1lN2ZMUlJRCkJQQ3lydFhiV3JONGowZGRIYTNqMGtyZHRHc1lueU9HL3ZVVVZyRURsZFcxaG5tYU9KZHErOVhORmtTR3lCU01lYS9WNktLVWZpQWYKUGNlZnNWOG5MZkkvOFMxSC9hakxONU1xN20vdkxSUlRBY1pWQzhMVks3a0xMUlJSSUNsUlJSV1FILy9aCg==
TEL;TYPE=cell:012 345 6789
TEL;TYPE=work:012 345 6789
END:VCARD

Apart from the photo not showing in both cases, I've also noticed that the company name which as set to "Moe's Co" has semi colons between each character in the output files. 除了在两种情况下均未显示的照片外,我还注意到设置为“ Moe's Co”的公司名称在输出文件中的每个字符之间都有半冒号。

Can anyone point advise me as to what I have done wrong ? 谁能指出我做错了什么? Any advice would be appreciated. 任何意见,将不胜感激。

Thanks in advance. 提前致谢。

In the second situation, you've double-encoded the Base64 data. 在第二种情况下,您已经对Base64数据进行了双重编码。 You don't need to use base64.encodestring on data because the vobject code does this for you upon setting encoding_param = 'b' . 您不需要在data上使用base64.encodestring ,因为vobject代码会在设置encoding_param = 'b'时为您执行此操作。 This wasn't obvious until I looked at the source to discover what was happening. 直到我查看源代码以发现正在发生的事情,这才变得显而易见。

As for your first situation with the URL-based approach, I'm yet to see a client (Evolution on Ubuntu, Outlook 2010 on Win 7) work correctly with that in a vCard. 关于使用基于URL的方法的第一种情况,我还没有看到客户端(Ubuntu上的Evolution,Win 7上的Outlook 2010)可以与vCard中的客户端正常工作。 Your clients are ignoring the URL, as are mine. 您的客户和我一样都忽略了该URL。

The vCard implementations summary at http://microformats.org/wiki/vcard-implementations gives an idea as to the quirks in different applications, though it isn't complete. http://microformats.org/wiki/vcard-implementations上的vCard实施摘要提供了关于不同应用程序中的怪癖的想法,尽管尚不完整。

For the company name, the value should be an array (so that you can have a department within a company for example). 对于公司名称,该值应该是一个数组(例如,可以在公司内设有部门)。 So just wrap the company name in brackets: 因此,只需将公司名称括在方括号中:

attr = card.add('org')
attr.value = ["Moe's Co"]

To obtain the image data, use the requests library instead. 要获取图像数据,请改用请求库。 Like @davidjb mentioned, you don't need to encode it into base64. 就像提到的@davidjb一样,您无需将其编码为base64。

import requests
attr.value = requests.get(photo_url).content

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM