将图像裁剪为完美的"广场像本机照片应用程序

时间:2015-11-30 12:37:56

标签: c# ios xamarin xamarin.ios uiimage

在处理从我们的某个服务器获取的嵌入式图像的功能时,其中一个要求是创建一个概览页面,其中显示所有图像,如iOS Native Photos App(正方形图块) ,以4/5的行和点击时,在屏幕范围内显示图像。

这已成功实施,但图像变形(图像方面从未被考虑过)。因此,他们要求我设计一种方法来裁剪图像,因此原始方面保持不变。

为了做到这一点,我想首先调整图像大小,直到宽度达到我想要的最大宽度((screenwidth - 10)/ 4 - 5)。

  • 如果图像的高度小于宽度,我将高度设置为等于宽度,并相应地裁剪宽度(方面不变)。
  • 如果图像的高度大于宽度,我只想裁剪高度。

这是我目前使用的方法:

//Images is an array/List with base64 strings
foreach (var image in Images)
{
    UIImage imageToAdd = UIImage.LoadFromData(NSData.FromArray(Convert.FromBase64String(image.Content)));

    var width = imageToAdd.Size.Width;
    var height = imageToAdd.Size.Height;

    //GlobalSupport.ScreenWidth is a static variable that contains the actual screensize
    var newWidth = (GlobalSupport.ScreenWidth - 10) / 4 - 5;

    var newHeight = height * newWidth / width;

    var widthToCrop = 0.0f;
    var heightToCrop = 0.0f;

    //If the new height is smaller than the new width, make the new height equal to the new width, and modify the new width accordingly.
    if (newHeight < newWidth)
    {
        newHeight = newWidth;
        newWidth = width * newHeight / height;

        widthToCrop = newWidth - newHeight;
    }
    //Or, if the new height is greater than the new width, just crop the height.
    else if (newHeight > newWidth)
    {
        heightToCrop = newHeight - newWidth;
    }

    UIGraphics.BeginImageContext(new SizeF(newWidth, newHeight));
    var cropRectangle = new RectangleF(-widthToCrop, -heightToCrop, newWidth, newHeight);
    imageToAdd.Draw(cropRectangle);
    imageToAdd = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();

    UIButton btnToAdd = new UIButton(new RectangleF(-widthToCrop, -heightToCrop, newWidth, newHeight));

    btnToAdd.SetBackgroundImage(imageToAdd, UIControlState.Normal);

    btnToAdd.TouchUpInside += (sender, e) =>
    {
        Task.Factory.StartNew(() =>
            {
                //Displays a loading spinner
                GlobalSupport.EnableLoadingOverlay(true, NSBundle.MainBundle.LocalizedString("txtOneMoment", "", ""));
            }).ContinueWith(task => InvokeOnMainThread(() =>
                {
                    //Navigate to the full-screen image viewer
                    this.NavigationController.PushViewController(
                        new VCDCMPhotoDetails(
                            UIImage.LoadFromData(
                                NSData.FromArray(
                                    Convert.FromBase64String(image.Content)))), true);

                    GlobalSupport.EnableLoadingOverlay(false, "");
                }));
    };

    //Add btn to the scrollable view's children
    scrollView.AddSubview(btnToAdd);
}

此方法效果很好,除了一件事:如果new height小于new widthnew heightnew width成功修改,但在ImageToAdd.Draw(RectangleF)之后{1}} Size的{​​{1}}仍然具有ImageToAdd值,而不是裁剪宽度(也就是说,如果我可以假设,如果我使用-20绘制图像作为其x值,宽度也会被修改为-20。

我不知道这是否是正确的方法。如果不是,那么欢迎所有帮助!如果这是正确的方法,但我错过了什么,请告诉我!提前谢谢!

裁剪图像时,x坐标等于图像的宽度减去缩略图的最大宽度:http://i.stack.imgur.com/uNm7k.png

裁剪后,图像仍然具有原始新宽度,而不是裁剪宽度:http://i.stack.imgur.com/rabeY.png

生成的图像网格:http://i.stack.imgur.com/opo2f.jpg

2 个答案:

答案 0 :(得分:2)

使用目标图像大小的大小创建图像视图时,您最容易做到的事情。然后将图像设置为它并设置内容模式以缩放纵横填充,并简单地创建视图的屏幕截图(您可以在网上找到非常简单的解决方案)。

从你的问题我看不出你是否有任何问题或者是什么问题。但有一件事困扰着我。这条线

RectangleF(-widthToCrop, -heightToCrop, newWidth, newHeight)

将以您始终获得图像右下角的方式裁剪它。你应该把它放在中心位置:

RectangleF(-widthToCrop*0.5, -heightToCrop*0.5, newWidth, newHeight)

好的我觉得我找到了你的问题。您计算的框架是您应该在其上绘制图像以将其放在正方形上的框架。但是当你开始图像上下文时,你应该将大小设置为正方形。因此,如果宽度较大,则大小应为(newHeight, newHeight),否则为(newWidth, newWidth)。按钮框对我来说也没有意义。为什么使用仅用于重绘图像的矩形?

答案 1 :(得分:2)

让我向您展示如何使用FILL操作裁剪图像的正确步骤。代码在Swift中,但是移植它应该没有问题:

    public static func resampleImageToSize(image: UIImage!, size: CGSize) -> UIImage {
        let originalWidth = image.size.width
        let originalHeight = image.size.height
        let originalRatio = originalWidth/originalHeight

        let targetRatio = size.width/size.height

        var targetFrame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)

        if originalRatio>targetRatio {
            // crop width
            let targetHeight = size.height
            let targetWidth = targetHeight * originalRatio
            targetFrame = CGRect(x: (size.width-targetWidth)*0.5, y: (size.height-targetHeight)*0.5, width: targetWidth, height: targetHeight)

        } else if originalRatio<targetRatio {
            // crop height
            let targetWidth = size.width
            let targetHeight = targetWidth / originalRatio
            targetFrame = CGRect(x: (size.width-targetWidth)*0.5, y: (size.height-targetHeight)*0.5, width: targetWidth, height: targetHeight)
        }

        UIGraphicsBeginImageContext(size)
        image.drawInRect(targetFrame)
        let outputImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return outputImage
    }

因此,这是一种采用原始图像并返回您选择尺寸的图像的通用方法。在您的情况下,这是您要显示的图标的大小。这里的操作是 fill ,如果您需要适合图像,您需要做的就是在{{1}中交换<>语句。