【问题标题】:jcrop: implement EXIF Orientationjcrop:实现 EXIF 方向
【发布时间】:2017-03-07 14:24:30
【问题描述】:

我的网站中有一个裁剪工具,用户可以上传图片并对其进行裁剪。

每当我上传手机拍摄的图片时,我都会遇到图像方向错误的情况。

HTML

<div class="modal-body">

            @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "formAjax", enctype = "multipart/form-data", action = "/ProfilePicture/Crop" }))
            {
                @Html.AntiForgeryToken()

                <label> Upload Photo: </label>
                <label class="btn btn-default btn-file">
                    Browse @Html.TextBoxFor(ModelIndex => ModelIndex.ProfilePic.MyFile, new { id = "file", type = "file", style = "display: none;" })
                </label>

                <br /><br />
                <div id="crop-image-area" style="display:none;">
                    <table border="0" cellpadding="0" cellspacing="5">
                        <tr>
                            <td>
                                <label>Preview: </label>
                                <div class="img-circle" style="width:100px;height:100px;overflow:hidden;margin-left:5px;">
                                    <canvas id="preview"></canvas>
                                </div>
                                <br />
                            </td>
                        </tr>
                        <tr>
                            <td>
                                <label>Crop Here: </label>
                                <img src="" id="cropbox" style="display: none;">
                            </td>
                        </tr>
                    </table>
                    <br />

                    <input type="hidden" id="cropPointX" name="cropPointX" />
                    <input type="hidden" id="cropPointY" name="cropPointY" />
                    <input type="hidden" id="imageCropWidth" name="imageCropWidth" />
                    <input type="hidden" id="imageCropHeight" name="imageCropHeight" />
                    <span>
                        <input type="submit" id="btnCrop" class="btn btn-success" value="Crop" />
                        <label>
                            <img id="loader" src="~/Content/images/loading.gif" style="display:none;" />
                        </label>
                    </span>
                </div>

            }
</div>

JS

$(function() {
    var jcrop_api;

    $("#file").change(function() {
        var reader = new FileReader();
        reader.onload = function(e) {
            $('#cropbox').show();
            $('#cropbox').attr('src', e.target.result);
            $('#cropbox').Jcrop({
                onChange: updatePreview,
                onSelect: getcroparea,
                boxWidth: 400,
                boxHeight: 400,
                aspectRatio: 1,
                bgOpacity: .4,
                setSelect: [80, 45, 100, 100]
            }, function() {
                //first attempt
                if (jcrop_api != null) {
                    jcrop_api.destroy();
                }
                //second attempt - even this does not work
                $(".jcrop-holder").not(":last").remove();
                jcrop_api = this;
            });

            $("#crop-image-area").hide();
            $("#crop-image-area").fadeIn("slow");

        }
        reader.readAsDataURL($(this)[0].files[0]);
        if ($('#cropbox').data('Jcrop')) {
            $('#cropbox').data('Jcrop').destroy();
            $('#cropbox').removeAttr('style');
        }

    });

    function updatePreview(c) {
        if (parseInt(c.w) > 0) {
            var imageObj = jQuery("#cropbox")[0];
            var canvas = jQuery("#preview")[0];
            var context = canvas.getContext("2d");
            context.beginPath();
            context.arc(50, 50, 50, Math.PI * 4, 0, true);
            context.clip();
            context.closePath();
            context.drawImage(imageObj, c.x, c.y, c.w, c.h, 0, 0, 100, 100);
        }
    };

    function getcroparea(c) {

        imageCropWidth = c.w;
        imageCropHeight = c.h;
        cropPointX = c.x;
        cropPointY = c.y;

        $('#cropPointX').val(Math.round(cropPointX))
        $('#cropPointY').val(Math.round(cropPointY))
        $('#imageCropWidth').val(Math.round(imageCropWidth))
        $('#imageCropHeight').val(Math.round(imageCropHeight))
    }

    function destroyCrop() {
        var jcropApi = $('#cropbox').data('Jcrop');
        if (jcropApi !== undefined) {
            jcropApi.destroy();
            $('#cropbox').attr('style', "").attr("src", "");
        }
    }

    function destroyPreview() {
        $('#preview').removeAttr('src');
    }

    function cropImage() {

        $("#loader").show();
        $('#formAjax').ajaxSubmit({
            type: 'POST',
            success: function(result) {
                $("#loader").hide();
                $('#myProfilePicModal').modal('hide');
                $("#crop-image-area").fadeOut("slow");
                destroyCrop();
                destroyPreview();
                $("#alert-success").show();
                $('#newImage').attr('src', 'data:image;base64,' + result.Photo);
                $('.img-avatar').attr('src', 'data:image;base64,' + result.Avatar);
                setTimeout(function() {
                    $("#alert-success").hide();
                }, 5000);
            },
            error: function() {
                $("#loader").hide();
                $('#myProfilePicModal').modal('hide');
                $("#crop-image-area").fadeOut("slow");
                destroyCrop();
                destroyPreview();
                $("#alert-fail").show();
                setTimeout(function() {
                    $("#alert-fail").hide();
                }, 5000);
            }
        });
    }
    $("#btnCrop").on("click", function(e) {
        e.preventDefault();
        cropImage();
    });
});

我不熟悉 EXIF 方向,请帮助我在我的代码中实现它。

【问题讨论】:

    标签: jquery exif jcrop


    【解决方案1】:

    我认为您的意思是您想从上传的图片中提取 EXIF 数据,然后旋转图片,使其始终处于某个位置。 对我来说,图像会发生什么情况还不清楚,例如,我用手机上传了一张以横向模式拍摄的照片,那张照片会倒置吗?当我上传使用 portret 模式制作的照片时会发生什么 这张照片会发生什么?因为我不知道这些信息,所以我无法为您创建完整的代码,但我可以帮助您上路。

    这是从客户端的图像中提取 EXIF 数据的 sn-p。这将在有人将图像添加到输入文件时触发。此 sn-p 由用户制作:https://stackoverflow.com/users/893432/ali

    function getOrientation(file, callback) {
      var reader = new FileReader();
      reader.onload = function(e) {
    
        var view = new DataView(e.target.result);
        if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
        var length = view.byteLength, offset = 2;
        while (offset < length) {
          var marker = view.getUint16(offset, false);
          offset += 2;
          if (marker == 0xFFE1) {
            if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
            var little = view.getUint16(offset += 6, false) == 0x4949;
            offset += view.getUint32(offset + 4, little);
            var tags = view.getUint16(offset, little);
            offset += 2;
            for (var i = 0; i < tags; i++)
              if (view.getUint16(offset + (i * 12), little) == 0x0112)
                return callback(view.getUint16(offset + (i * 12) + 8, little));
          }
          else if ((marker & 0xFF00) != 0xFF00) break;
          else offset += view.getUint16(offset, false);
        }
        return callback(-1);
      };
      reader.readAsArrayBuffer(file);
    }
    
    // usage:
    var input = document.getElementById('input');
    input.onchange = function(e) {
      getOrientation(input.files[0], function(orientation) {
        alert('orientation: ' + orientation);
      });
    }
    &lt;input id='input' type='file' /&gt;

    如果图片包含EXIF数据,这个sn-p会从图片中提取EXIF数据,你可以得到的响应值如下:

    -2: not jpeg
    -1: not defined
    

    因此,当它不是 jpeg 时,您将得到 -2,而根本没有图片时,您将得到 -1。如果它有效,您将在图像中获得响应之一,并且您必须使用 jcrop 旋转图像。

    假设您得到代码 8 并且图像向右旋转 45 度,您可以使用此代码将其向左旋转 45 度,这样您就知道它是直立的。

    var jcp = $("#input").Jcrop('api');
    jcp.ui.stage.setAngle(45).redraw();
    

    据我所知,此 sn-p 仅适用于 jCrop 2+,您也可以尝试这样做:

    $('#cropbox').Jcrop({
            onChange: updatePreview,
            onSelect: getcroparea,
            boxWidth: 400,
            boxHeight: 400,
            setAngle: 45,
            aspectRatio: 1,
            bgOpacity: .4,
            setSelect: [80, 45, 100, 100]
        }
    

    但我没有测试过后者。

    你最好的选择是:

    1. 使用我提供的 sn-p 提取图像的旋转,根据你得到的数字计算你需要多少旋转图像/翻转图像
    2. 然后使用 jCrop 2.0 版重建您的 jCrop 解决方案,并使用我提供的 2 行 sn-p 来旋转您的图像。

    这是另一种解决方案,它要求您也稍微更改一下 jCrop 代码以允许旋转。 Make Jcrop tracker not rotate when cropping a rotated image

    【讨论】:

    • 嗨,@gertjan 感谢您的回答。抱歉,如果您不清楚我的问题。我想要发生的是,每当用户上传图像时,画布上显示的图像将具有正确的方向。因为到目前为止它输出了错误的方向8(基于上图)。
    • 嗨@Terence,这意味着您必须使用 setAngle 将图像旋转 270 度,或者使用我的回答 jcp.ui.stage.setAngle(45).redraw();
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 2018-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    相关资源
    最近更新 更多