问题
I have a web2py based portal where a group of annotators provide text labels and bounding-boxes related information for the various images shown to them. I'd like to get this information in the form of XML files (one-per-image) and add a download-annotations functionality to the portal which serves a ZIP file containing all these XML files. I am able to create a zip-download from the portal but unzipping the same throws the following error :
mohit@nightfury13:~/Downloads$ unzip Arabic\ Set1-Arabic_annotations.zip
Archive: Arabic Set1-Arabic_annotations.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of Arabic Set1-Arabic_annotations.zip or
Arabic Set1-Arabic_annotations.zip.zip, and cannot find Arabic Set1-Arabic_annotations.zip.ZIP, period.
Following is the code I've written to perform this task. Can someone point out what am I doing wrong? - First half of the code is preparation of the dataset-XML-string (you may skip that). Second half is the zip pipeline.
@auth.requires_login()
def prepare_dataset():
import os
from PIL import Image
import zipfile, cStringIO
# Check if a valid data-id was passed.
if not request.vars.data_id:
session.flash = 'No dataset selected for download'
redirect(URL('default', 'select_db?redirect=1'))
# Create the annotation-data in a proper format.
else:
data_id = int(request.vars.data_id)
dataset = db(db.Datasets.id==data_id).select()[0]
root_path = dataset['data_path'].split('cropped')[0]
root_images = [i for i in os.listdir(root_path) if i.endswith('.jpg') or i.endswith('.jpeg') or i.endswith('.png')]
content = {}
imgs_data = db((db.Images.data_id==data_id)&(db.FinalLabels.img_id==db.Images.id)).select()
for img_data in imgs_data:
label = img_data['FinalLabels']['label']
if 'bad' not in [i.lower() for i in label.split()]:
img_name = img_data['Images']['img_name']
root_img_name = img_name.split('_')[0]
xmin, ymin, xmax, ymax = img_name.split('.')[0].split('_')[2:]
if root_img_name not in content:
r_im_name = [i_name for i_name in root_images if root_img_name in i_name][0] # This one also has the extension
root_im = Image.open(os.path.join(root_path, r_im_name))
r_depth = 3
if not root_im.mode=='RGB':
r_depth = 1
r_width, r_height = root_im.size
content[root_img_name] = {'name':r_im_name, 'depth':r_depth, 'width':r_width, 'height':r_height, 'crops':[{'label':label, 'xmin':xmin, 'ymin':ymin, 'xmax':xmax, 'ymax':ymax}]}
else:
content[root_img_name]['crops'].append({'label':label, 'xmin':xmin, 'ymin':ymin, 'xmax':xmax, 'ymax':ymax})
# Compress img-annotation data (content) to zip and export
zip_chunks = cStringIO.StringIO()
zipf = zipfile.ZipFile(zip_chunks, "w", compression=zipfile.ZIP_DEFLATED)
for im_name in content:
root_im = content[im_name]
root_folder = filter(None, root_path.split('/'))[-1]
xml_str = """<annotation>
<folder>%s</folder>
<filename>%s</filename>
<path>%s</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>%s</width>
<height>%s</height>
<depth>%s</depth>
</size>
<segmented>0</segmented>""" % (root_folder, im_name, root_im['name'], root_im['width'], root_im['height'], root_im['depth'])
for crop in root_im['crops']:
xml_str+="""
<object>
<name>%s</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>%s</xmin>
<ymin>%s</ymin>
<xmax>%s</xmax>
<ymax>%s</ymax>
</bndbox>
</object>""" % (crop['label'], crop['xmin'], crop['ymin'], crop['xmax'], crop['ymax'])
xml_str+='\n</annotation>'
zipf.writestr(im_name+'.xml', xml_str)
zipf.close()
zip_name = dataset['data_name']+'_annotations.zip'
file_header = 'attachment; filename='+zip_name
response.headers['Content-Type'] = 'application/zip'
response.headers['Content-Disposition'] = file_header
return zipf
回答1:
ZipFile
is writing the data to the zip_chunks
StringIO
object, so you must return zip_chunks.getvalue()
, not zipf
.
来源:https://stackoverflow.com/questions/44804747/web2py-downloading-zip-file-created-by-cstringio-text-strings-in-controller