【问题标题】:Php Imagick Crop Image From Variable Center PointPhp Imagick 从可变中心点裁剪图像
【发布时间】:2018-03-28 06:25:21
【问题描述】:

我正在构建一个 Croppie 的实现作为 AngularJS 指令,以便为用户提供一个 UI 来裁剪他们的个人资料图像。

我的后端是 PHP,我需要一种将 UI 选择反映在服务器端操作中的方法。

我的图像中心有一个 150 x 150 的正方形,链接的 Croppie 示例同样显示。但是,正如您所见,您可以移动和缩放图像,这意味着在 Imagick 中从中心进行裁剪并不总是有效,具体取决于用户如何围绕中心点放置图像。

我知道我可以缩放图像,然后在 Imagick 中从中心裁剪,但我如何解释图像也会被翻译的事实?

当我在我的实现中移动图像时,我得到以下数据点来解析并发送到服务器:

{transform: "translate3d(-60px, -121px, 0px) scale(1)"}

这表明,例如,图像已沿 X 和 Y 轴移动,并且尚未缩放。如何在 Imagick 中相应地移动图像的中心?

谢谢!

编辑:

我看到这些命令:Imagick::cropThumbnailImageImagick::cropImage 是否有某种方法可以将它们组合在一起,使裁剪区域在图像缩放时保持在中心,并且图像可以在 x 或 y 轴上移动?

编辑 2

好吧,我发现我需要使用 Imagick::cropImageImagick::scaleImage 的组合,但我无法确定要发送到服务器的正确数学。

我附上了一张图片,以便您了解我的意思,我已经非常接近了,但某些图片的裁剪已关闭:

我的 HTML 是这样的:

<div class="viewBox">
<img class="bigTuna">
<div class="enclosedCrop small"></div>
<div class="overlay small"></div>
</div>

您看到的图像是.bigTuna,我想使用.encloseCrop.small(即圆圈)对其进行裁剪。

我使用以下方法计算图像相对于图像比例 (.bigTuna) 的偏移量(我可以在 .encloseCrop.small 周围拖动)。 .encloseCrop.small 的偏移量为.viewBox,图片占据了整个.viewBox 一个max-width: 100%;

因为图像有 widthnaturalWidthgetBoundingClientRect().width以及高度的相应属性t)我不确定如何完成这个我可以发送给 Imagick XY 用于 cropImage() 参数。

这是我得到的最接近的:

var Xvalue = (angular.element(".enclosedCrop")[0].offsetLeft + ( -1 * $scope.matrixobject.x )) * ((angular.element('.bigTuna')[0].getBoundingClientRect().width/angular.element('.bigTuna')[0].width)*(angular.element('.bigTuna')[0].naturalWidth/angular.element('.bigTuna')[0].width));
var Yvalue = (angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y ))  * ((angular.element('.bigTuna')[0].getBoundingClientRect().height/angular.element('.bigTuna')[0].height)*(angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].height));

边界宽度除以宽度是比例因子,但我相信我也需要以某种方式考虑自然宽度。问题是您在Croppie-like 指令所在的模态中看到的图像已经被缩放,因为它不是自然尺寸。最重要的是,我正在使用 CSS 变换再次缩放这个(已经)缩放的图像。

但是当我将图像发送到 PHP 时,它不知道这一点。我只是收到自然尺寸并想知道如何裁剪它。我需要该裁剪来反映 UI 裁剪。

$scope.matrixobject.x 是图像变换的值,在这种情况下,它被平移的像素数量。我可以很好地得到所有这些值,我只是不知道使用这些值的方程实际上是正确的。

编辑 3:

我已经像这样改进了我的方程式,但是这个方程式,虽然它对我来说最有意义,但让我完全没有收获。

var Xvalue = (angular.element(".enclosedCrop")[0].offsetLeft + ( -1 * $scope.matrixobject.x )) * (angular.element('.bigTuna')[0].naturalWidth/angular.element('.bigTuna')[0].getBoundingClientRect().width);
var Yvalue = (angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y ))  * (angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].getBoundingClientRect().height);

该等式首先尝试从图像容器的顶部和左侧获取 150 x 150 圆 (.enclosedCrop) 的偏移量

在高度的情况下,如下所示:

angular.element(".enclosedCrop")[0].offsetTop + ( -1 * $scope.matrixobject.y )

该等式摘录的第一部分得到 offsetTop,它将保持不变,因为 .enclosedCrop 本身在容器的中心是静止的。 $scope.matrixobject.y 是容器周围图像的变换,通过反转它,如果 .enclosedCrop 在图像周围移动,我们可以获得所需的变换。通过将此添加到偏移量中,我们可以知道图像上的裁剪位置。

但是,偏移量和变换是相对于容器中图像的大小 (max-width:100%) 这意味着它们需要缩放以反映图像的自然大小以及使用 CSS scale 属性可能发生的任何变换。

所以我将偏移量乘以这个:

* (angular.element('.bigTuna')[0].naturalHeight/angular.element('.bigTuna')[0].getBoundingClientRect().height);

自然高度除以图像的高度。重要的是,这个“图像高度”源自getBoundingClientRect(),这意味着它考虑了 CSS 缩放。

那么我的逻辑有什么问题呢?我在整个图像上都得到了裁剪,而不是在我指定的坐标中。

编辑 4:

我得到了非常接近给出的以下等式,我不太明白(来自 Croppie 的源代码)

var Xvalue = angular.element(".enclosedCrop")[0].getBoundingClientRect().left - angular.element(".bigTuna")[0].getBoundingClientRect().left + angular.element(".enclosedCrop")[0].offsetWidth + (angular.element(".enclosedCrop")[0].getBoundingClientRect().width - angular.element(".enclosedCrop")[0].offsetWidth) / 2;
var Yvalue = angular.element(".enclosedCrop")[0].getBoundingClientRect().top - angular.element(".bigTuna")[0].getBoundingClientRect().top + angular.element(".enclosedCrop")[0].offsetHeight + (angular.element(".enclosedCrop")[0].getBoundingClientRect().height - angular.element(".enclosedCrop")[0].offsetHeight) / 2;
Xvalue = parseFloat(Xvalue).toFixed(0);
Yvalue = parseFloat(Yvalue).toFixed(0);

但是它总是偏离几个像素,通常稍微向下和向右。

谁能解释一下这个方程式,以便我更好地编辑它并找出错误?

【问题讨论】:

  • 作为替代方案,您可以在客户端裁剪图像并将其发送到服务器
  • 我认为你应该只发送缩放后的 x、y 和图像尺寸。从服务器上的图像中读取其尺寸,然后计算所需的值。 OT:使用&lt;canvas&gt;在客户端生成图像。
  • @RomanCortes 我更愿意在服务器端进行裁剪。
  • @bato3 你能解释一下你建议我将哪些数据点发送到服务器吗?
  • 你需要发送 offset(x, y), size(width, height) 然后可以处理原始图像和 imagemagick

标签: php angularjs image math imagick


【解决方案1】:

css 和 js 的这个棘手部分。

标记 html

<div class="viewBox layer-image">
  <img class="bigTuna">
  <div class="enclosedCrop small"></div>
  <div class="overlay small"></div>
</div>

CSS

.layer-image {
  background-image: url('sample/image.png');
  position: relative;
  height: 800px; /* actual height sample*/
  weight: 800px; /* actual weight sample*/
}

.enclosedCrop.small {
  position: absolute;
}

我们设置类 layer-image 具有背景图像和相对位置。你知道基本绝对位置是相对的。

Javascript

对于拖动、调整大小,您可以使用自己喜欢的库或使用自己的代码。最大的问题是如何获得 x 和 y。如果您看到代码,我们已经知道如何获取 x y。想象 x y 从左上角开始。所以你只需要从图层图像中获取 .enclosedCrop.small 的边距顶部和 .enclosedCrop.small 的左边距。例如:

var offsetLayerBase = $('.enclosedCrop.small').offset();
var offsetCropping = $('.enclosedCrop.small').offset();
var yPositionCrop = offsetCropping.top - offsetLayerBase.top;
var xPositionCrop = offsetCropping.left - offsetLayerBase.left;

offsetLayerBase 设置为窗口的基础(如果有 css 自定义,则需要任何自定义)。

如果适合你,请告诉我。干杯;)

【讨论】:

  • 我知道如何再次获取 x 和 y 我从我的 UI 中获得了所有变量我只是不知道如何转换到服务器,它只获取原始图像并且需要缩放到自然宽度的坐标和高度。
  • @SummerDeveloper 你想在客户端还是服务器上计算?
  • 如果你看到演示,他们使用画布作为图像(大部分),所以我只是想用 html 5 来计算
  • 如果您在演示上传中看到,它会按相对图像缩放。有时会因身高或体重而固定。我认为取决于肖像或风景。当您上传时,它会缩放。这对于定位很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-03
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 2014-05-26
  • 2019-05-13
  • 1970-01-01
相关资源
最近更新 更多