0

fileupload jQuery プラグインを使用して、自分のサイトにファイルをアップロードしています。ネットワークの使用を最小限に抑えるために、アップロードする前に画像のサイズを変更したいのですが、これまでのところ完全な例を見つけることができませんでした。これは私の簡単なテストコードです。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="/static/js/cloudinary/jquery.ui.widget.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/load-image.min.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/canvas-to-blob.min.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/jquery.iframe-transport.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/jquery.fileupload.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/jquery.fileupload-ip.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/jquery.fileupload-process.js" type="text/javascript"></script>
<script src="/static/js/cloudinary/jquery.fileupload-validate.js" type="text/javascript"></script>

...

$("#fileupload")
    .fileupload({
        disableImageResize: false,
        imageMaxWidth: 8000,
        imageMaxHeight: 6000,
        acceptFileTypes: /(\.|\/)(gif|jpe?g|png|bmp|ico)$/i,
        maxFileSize: 20000000, // 20MB
        process: [
            {
                action: 'load',
                fileTypes: /^image\/(gif|jpeg|png)$/,
                maxFileSize: 20000000 // 20MB
            },
            {
                action: 'resize',
                maxWidth: 200,
                maxHeight: 150,
                minWidth: 80,
                minHeight: 60
            },
            {
                action: 'save'
            }
        ]

    });
4

3 に答える 3

0

複雑なアップローダーのためにすべてのピースをまとめるのは複雑な作業なので、ここで私のソリューションを共有します。

この回答の要素

  • ページごとに任意の数のアップローダーを配置できます。この例では、ページに Driving と Medical という 2 つの個別のアップロード ボタンあります

  • アップロードする前に、クライアント側で画像のサイズを 1024 x 1024 に変更します。

  • アップロード中にユーザーにアップロードされた画像のプレビューを表示する

  • Jinja 2 テンプレートとしての HTML コード

  • Bootstrap 3.x をテーマにしたアップロード ボタンとアップロードの進行状況バー

  • ピラミッド スタイルの JavaScript リソースの読み込み

1 つの個別のアップロード ウィジェットをレンダリングする Jinja 2 HTML テンプレート コード ( upload_snippet.html)。パラメータidnameおよびupload_targetを使用します。

<div id="upload-{{ id }}">

    <div id="medical-license" class="btn btn-block btn-file">
        <i class="fa fa-camera"></i> {{ name }}

        <input type="file" class="file-select" data-url="{{ upload_target }}" data-param-name="{{ id }}">
    </div>
    <p>
        <div class="preview" style="display: none"></div>
    </p>

    <div class="progress progress-xxx" style="display: none">
        <div class="progress-bar progress-bar-striped progress-bar-xxx active" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
        </div>
    </div>

    <div class="success" style="display: none">

        <div class="alert alert-success">
            {{ name }} upload completed
        </div>
    </div>

    <div class="error" style="display: none">

        <div class="alert alert-danger">
            <span class="error-message"></span>
        </div>
    </div>
</div>

2 つのアップロード ウィジェットを構築するメインの Jinja 2HTML テンプレート。Bootstrap ボタンのようにスタイルを設定します。

{% extends "site/base.html" %}

{% block extra_head %}
    <style>
    /* http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/ */
    .btn-file {
        position: relative;
        overflow: hidden;
    }
    .btn-file input[type=file] {
        position: absolute;
        top: 0;
        right: 0;
        min-width: 100%;
        min-height: 100%;
        font-size: 100px;
        text-align: right;
        filter: alpha(opacity=0);
        opacity: 0;
        outline: none;
        background: white;
        cursor: inherit;
        display: block;
    }

    .preview {
        width: 128px;
        height: 128px;
        margin: 0 auto;
    }
    </style>
{% endblock %}

{% block content_section %}
    <!-- Header -->
    <section id="license-information">

        <div class="row">
            <div class="col-md-12">
                 <h1>Upload information</h1>
            </div>
        </div>

        <div class="row">
            <div class="col-md-6">

                {% with id='medical', name='Medical license' %}
                    {% include "upload_snippet.html" %}
                {% endwith %}

                {% with id='driving', name='Driving license or other id' %}
                    {% include "upload_snippet.html" %}
                {% endwith %}


            </div>
        </div>

    </section>
{% endblock content_section %}

{% block custom_script %}

 <!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="{{ 'xxx:static/jquery-file-upload/js/vendor/jquery.ui.widget.js'| static_url }}"></script>

<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="{{ 'xxx:static/jquery-file-upload/js/load-image.all.min.js' | static_url }}"></script>

<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="{{ 'xxx:static/jquery-file-upload/js/canvas-to-blob.js' | static_url }}"></script>

<!-- The basic File Upload plugin -->
<script src="{{ 'xxx:static/jquery-file-upload/js/jquery.fileupload.js' | static_url }}"></script>
<!-- The File Upload processing plugin -->
<script src="{{ 'xxx:static/jquery-file-upload/js/jquery.fileupload-process.js' | static_url }} "></script>
<!-- The File Upload image preview & resize plugin -->
<script src="{{ 'xxx:static/jquery-file-upload/js/jquery.fileupload-image.js' | static_url }} "></script>

<script>
window.nextURL = "{{ after_both_files_are_uploaded }}"
</script>

<script>
    "use strict";

    var state = {
        medical: false,
        driving: false
    }

    // Make styled elements to trigger file input
    $(document).on('change', '.btn-file :file', function() {
        var input = $(this),
            numFiles = input.get(0).files ? input.get(0).files.length : 1,
            label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
        input.trigger('fileselect', [numFiles, label]);
    });

    function checkForward() {
        // Is all upload done and we can go to the next page?
        if(state.medical && state.driving) {
            window.location = window.nextURL;
        }
    }

    function doUpload(name) {

        var baseElem = $("#upload-" + name);

        if(baseElem.length != 1) {
            throw new Error("Wooops, bad DOM tree");
        }

        function onStart() {
            baseElem.find(".progress").show();
            baseElem.find(".error").hide();
            baseElem.find(".success").hide();
        }

        function onDone(result, data) {
            baseElem.find(".progress").hide();
            if(data.result.status == "ok") {
                // All ok, check if we can proceed
                baseElem.find(".success").show();
                state[name] = true;
                checkForward();
            } else {
                // Server responded us it didn't like the file and gave a specific error message
                var msg = data.result.message;
                baseElem.find(".error-message").text(msg);
                baseElem.find(".error").show();
                state[name] = false;
            }
        }

        function onError(result, data) {
            baseElem.find(".progress").hide();
            baseElem.find(".error-message").text("Upload could not be completed. Please contact the support.");
            baseElem.find(".error").show();
            state[name] = false;
        }

        function onProgress(e, data) {
            var progress = parseInt(data.loaded / data.total * 100, 10);
            baseElem.find(".progress-bar").css("width", progress + "%");
        }

        function onPreview(e, data) {
            var canvas = data.files[0].preview;
            var dataURL = canvas.toDataURL();
            baseElem.find(".preview").css("background-image", 'url(' + dataURL +')');
            baseElem.find(".preview").css({width: canvas.width, height: canvas.height});
            baseElem.find(".preview").show();
        }

        var upload = baseElem.find('.file-select');
        upload.fileupload({
            dataType: 'json',
            // Enable image resizing, except for Android and Opera,
            // which actually support image resizing, but fail to
            // send Blob objects via XHR requests:
            // disableImageResize: /Android(?!.*Chrome)|Opera/
            //    .test(window.navigator && navigator.userAgent),
            disableImageResize: false,
            imageMaxWidth: 1024,
            imageMaxHeight: 1024,
            imageCrop: false, // Force cropped images,
            previewMaxWidth: 128,
            previewMaxHeight: 128,
            maxFileSize: 7*1024*1024
        });

        upload.bind("fileuploaddone", onDone);
        upload.bind("fileuploadstart", onStart);
        upload.bind("fileuploadfail", onError);
        upload.bind("fileuploadprogress", onProgress);
        upload.bind('fileuploadprocessalways', onPreview);

    }

    $(document).ready(function() {
        doUpload("medical");
        doUpload("driving");
    });
</script>

{% endblock %}

次に、ペイロードをデコードし、ユーザーがランダムなファイルではなく画像をアップロードしたことを確認する単純なサーバー側の Pyramid ビュー。結果は、JavaScript がデコードできる JSON 応答です。

@view_config(route_name='upload_target', renderer='json')
def upload_target(request):
    """AJAX upload of driving license and medical images."""
    if "medical" in request.params:
        license = "medical"
        files = request.params["medical"]
    elif "driving" in request.params:
        license = "driving"
        files = request.params["driving"]
    else:
        raise RuntimeError("Unsupported upload type")

    # # TODO: use chunks, do not buffer 100%
    # path = user.prepare_upload_path()
    storage = io.open(where_to_save, "wb")
    fp = files.file

    # Now we test for a valid image upload
    image_test = imghdr.what(fp)
    if image_test == None:
        return {"status": "fail", "message": "Only JPEG and PNG image file upload supported."}

    fp.seek(0)
    data = fp.read()
    assert len(data) > 0
    storage.write(data)
    storage.close()

    return {"status": "ok"}
于 2015-04-26T19:25:16.747 に答える