从变量中心点裁剪Php Imagick图像

4
我正在构建一个Croppie的实现作为AngularJS指令,为用户提供裁剪其个人资料图像的UI。
我的后端是PHP,我需要一种方法来反映服务器端操纵中的UI选择。
我在我的图像中心有一个150x150的正方形,正如链接的Croppie示例所示。但是,正如您可以看到的那样,您可以移动和缩放图像,这意味着从Imagick的中心进行裁剪并不总是有效,具体取决于用户如何将其图像定位在中心点周围。
我知道我可以缩放图像,然后在Imagick中从中心进行裁剪,但是如何考虑到图像也将被平移?
当我在我的实现中移动图像时,我得到以下数据点以解析并发送到服务器:
{transform: "translate3d(-60px, -121px, 0px) scale(1)"}
例如,这显示图像已沿X和Y轴移动,并且未缩放。我如何相应地在Imagick中移动图像的中心?
谢谢!

编辑:

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

编辑2:

好的,我找到了需要使用Imagick::cropImageImagick::scaleImage的组合,但我无法找出发送到服务器的正确数学公式。

我附上一张图片,让你看看我的意思,我已经非常接近了,但是某些图片的剪裁位置不对:

Cropping An Image

我的HTML如下:

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

您所看到的图片,我想使用.encloseCrop.small进行裁剪,它是一个圆形,而这张图片是.bigTuna
我正在使用以下代码计算图像的偏移量(我可以将其拖动到.encloseCrop.small周围),相对于图像的比例(.bigTuna)。 .encloseCrop.small的偏移量是.viewBox,而图像占据了整个.viewBox,具有max-width: 100%; 由于图像具有widthnaturalWidthgetBoundingClientRect().width(以及相应的高度属性),我不确定如何完成此操作,以便我可以仅向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));

边界宽度除以宽度是比例因子,但我认为还需要考虑自然宽度。问题在于,在类似于指令所在的模态窗口中看到的图像已经按比例缩放,因为它不是自然尺寸。此外,我正在使用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 )

方程式摘录的第一部分获取了.enclosedCropoffsetTop,由于它本身位于容器中心而保持不变。 $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);

然而,它总是少几个像素,通常稍微向下和向右。有人能解释一下这个方程式,以便我可以更好地编辑它并找到错误吗?

作为一种替代方案,您可以在客户端裁剪图像并将其已经裁剪好的发送到服务器。 - user8811940
我认为你应该在缩放后只发送x、y和图像尺寸。从服务器上的图像中读取其尺寸,然后计算所需的值。OT:使用<canvas>在客户端生成图像。 - bato3
@RomanCortes 我更倾向于在服务器端进行裁剪。 - Summer Developer
{btsdaf} - Summer Developer
1
你需要发送偏移量(x, y)、尺寸(width, height),然后才能使用原始图像和ImageMagick进行操作。 - Artem Ilchenko
显示剩余3条评论
1个回答

0

这是一个涉及到 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从左上角开始。所以你需要做的就是从layer-image中获取.enclosedCrop.small的margin-top和margin-left。例如:

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中的所有变量,只是不知道如何将其转换为服务器,因为服务器仅接收原始图像,并需要按自然宽度和高度缩放的坐标。 - Summer Developer
@SummerDeveloper 你想在客户端还是服务器上进行计算? - hendrathings
如果您看演示,他们使用画布来处理图像(大多数情况下),因此我认为可以使用HTML 5进行计算。 - hendrathings
如果您看到演示上传,它会按照图像相对缩放。有时候高度或重量固定。这取决于是纵向还是横向,我想。当您上传时,它会自动缩放。这对于定位非常重要。 - hendrathings

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接