web2py:在控制器中下载由cStringIO文本字符串创建的zip文件 [英] web2py : downloading zip file created by cStringIO text strings in controller

查看:80
本文介绍了web2py:在控制器中下载由cStringIO文本字符串创建的zip文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于web2py的门户,其中一组注释器为显示给他们的各种图像提供文本标签和边框相关的信息。我想以XML文件的形式获取此信息(每个图像一个),并向门户网站添加下载注释功能,该门户网站提供包含所有这些XML文件的ZIP文件。我可以从门户网站创建一个zip下载文件,但是将其解压缩会引发以下错误:

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.

以下是我为执行此任务而编写的代码。有人可以指出我在做什么错吗?
-代码的前半部分是准备数据集XML字符串(您可以跳过)。下半部分是zip管道。

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


推荐答案

ZipFile 正在将数据写入 zip_chunks StringIO 对象,因此您必须返回 zip_chunks.getvalue(),而不是 zipf

ZipFile is writing the data to the zip_chunks StringIO object, so you must return zip_chunks.getvalue(), not zipf.

这篇关于web2py:在控制器中下载由cStringIO文本字符串创建的zip文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆