jcrop:实现 EXIF 方向
Posted
技术标签:
【中文标题】jcrop:实现 EXIF 方向【英文标题】:jcrop: implement EXIF Orientation 【发布时间】: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 方向,请帮助我在我的代码中实现它。
【问题讨论】:
【参考方案1】:我认为您的意思是您想从上传的图片中提取 EXIF 数据,然后旋转图片,使其始终处于某个位置。 对我来说,图像会发生什么情况还不清楚,例如,我用手机上传了一张以横向模式拍摄的照片,那张照片会倒置吗?当我上传使用 portret 模式制作的照片时会发生什么 这张照片会发生什么?因为我不知道这些信息,所以我无法为您创建完整的代码,但我可以帮助您上路。
这是从客户端的图像中提取 EXIF 数据的 sn-p。这将在有人将图像添加到输入文件时触发。此 sn-p 由用户制作:https://***.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);
);
<input id='input' type='file' />
如果图片包含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]
但我没有测试过后者。
你最好的选择是:
-
使用我提供的 sn-p 提取图像的旋转,根据你得到的数字计算你需要多少旋转图像/翻转图像
然后使用 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();
以上是关于jcrop:实现 EXIF 方向的主要内容,如果未能解决你的问题,请参考以下文章