gpt4 book ai didi

ios - 使用具有图像全分辨率的 bezierpath 屏蔽图像

转载 作者:行者123 更新时间:2023-12-01 18:37:58 25 4
gpt4 key购买 nike

enter image description here
嗨,我有一个路径(形状)和一个高分辨率图像。我将高分辨率图像设置为在我绘制路径的 View 内的 AspectFit,我想用路径掩盖图像,但以图像的全分辨率,而不是我们看到路径的分辨率。问题是,当我不将它们放大以进行高分辨率 mask 时,它可以完美地工作,但是当我这样做时,一切都搞砸了。面具被拉伸(stretch),起源没有意义。

enter image description here

我想要的只是能够以相同的图像纵横比(以图像的全分辨率)放大路径并正确定位它,以便它可以正确掩盖高分辨率图像。
我试过这个:

Masking CGContext with a CGPathRef?

还有这个

Creating mask with CGImageMaskCreate is all black (iphone)

还有这个

Clip UIImage to UIBezierPath (not masking)

当我尝试掩盖高质量图像(大于屏幕分辨率)时,这些都不能正常工作

编辑 我在 github 上发布了一个工作项目,以显示正常质量 mask (以屏幕分辨率)和高质量 mask (以图像分辨率)之间的问题。我真的很感激任何帮助。
https://github.com/Reza-Abdolahi/HighResMasking

最佳答案

如果我正确理解您的问题:

  • 您有一个 ImageView ,其中包含可能已使用 UIViewContentModeScaleAspectFit 缩小(甚至放大)的图像.
  • 您有一个贝塞尔路径,其点位于该 ImageView 的几何(坐标系)中。

  • 现在您想要创建一个图像的副本,以原始分辨率,被贝塞尔路径掩盖。

    我们可以将图像视为具有自己的几何形状,原点位于图像的左上角,沿每个轴的一个单位为一个点。所以我们需要做的是:
  • 创建一个足够大的图形渲染器以在不缩放的情况下绘制图像。这个渲染器的几何就是图像的几何。
  • 将贝塞尔路径从 View 几何体转换为渲染器几何体。
  • 将转换后的路径应用到渲染器的剪辑区域。
  • 将图像(未转换)绘制到渲染器中。

  • 第 2 步是困难的,因为我们必须想出正确的 CGAffineTransform .在切面拟合场景中,变换不仅需要缩放图像,还可能沿 x 轴或 y 轴(但不能同时)平移图像。但是让我们更笼统地支持其他 UIViewContentMode设置。这是一个可以让您询问 UIImageView 的类别对于将 View 几何中的点转换为图像几何中的点的变换:
    @implementation UIImageView (ImageGeometry)

    /**
    * Return a transform that converts points in my geometry to points in the
    * image's geometry. The origin of the image's geometry is at its upper
    * left corner, and one unit along each axis is one point in the image.
    */
    - (CGAffineTransform)imageGeometryTransform {
    CGRect viewBounds = self.bounds;
    CGSize viewSize = viewBounds.size;
    CGSize imageSize = self.image.size;

    CGFloat xScale = imageSize.width / viewSize.width;
    CGFloat yScale = imageSize.height / viewSize.height;
    CGFloat tx, ty;
    switch (self.contentMode) {
    case UIViewContentModeScaleToFill: tx = 0; ty = 0; break;
    case UIViewContentModeScaleAspectFit:
    if (xScale > yScale) { tx = 0; ty = 0.5; yScale = xScale; }
    else if (xScale < yScale) { tx = 0.5; ty = 0; xScale = yScale; }
    else { tx = 0; ty = 0; }
    break;
    case UIViewContentModeScaleAspectFill:
    if (xScale < yScale) { tx = 0; ty = 0.5; yScale = xScale; }
    else if (xScale > yScale) { tx = 0.5; ty = 0; xScale = yScale; }
    else { tx = 0; ty = 0; imageSize = viewSize; }
    break;
    case UIViewContentModeCenter: tx = 0.5; ty = 0.5; xScale = yScale = 1; break;
    case UIViewContentModeTop: tx = 0.5; ty = 0; xScale = yScale = 1; break;
    case UIViewContentModeBottom: tx = 0.5; ty = 1; xScale = yScale = 1; break;
    case UIViewContentModeLeft: tx = 0; ty = 0.5; xScale = yScale = 1; break;
    case UIViewContentModeRight: tx = 1; ty = 0.5; xScale = yScale = 1; break;
    case UIViewContentModeTopLeft: tx = 0; ty = 0; xScale = yScale = 1; break;
    case UIViewContentModeTopRight: tx = 1; ty = 0; xScale = yScale = 1; break;
    case UIViewContentModeBottomLeft: tx = 0; ty = 1; xScale = yScale = 1; break;
    case UIViewContentModeBottomRight: tx = 1; ty = 1; xScale = yScale = 1; break;
    default: return CGAffineTransformIdentity; // Mode not supported by UIImageView.
    }

    tx *= (imageSize.width - xScale * (viewBounds.origin.x + viewSize.width));
    ty *= (imageSize.height - yScale * (viewBounds.origin.y + viewSize.height));
    CGAffineTransform transform = CGAffineTransformMakeTranslation(tx, ty);
    transform = CGAffineTransformScale(transform, xScale, yScale);
    return transform;
    }

    @end

    有了这个,我们可以编写屏蔽图像的代码。在我的测试应用程序中,我有一个 UIImageView 的子类命名为 PathEditingView处理贝塞尔路径编辑。所以我的 View Controller 像这样创建蒙版图像:
    - (UIImage *)maskedImage {
    UIImage *image = self.pathEditingView.image;
    UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init];
    format.scale = image.scale;
    format.prefersExtendedRange = image.imageRendererFormat.prefersExtendedRange;
    format.opaque = NO;
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:image.size format:format];
    return [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
    UIBezierPath *path = [self.pathEditingView.path copy];
    [path applyTransform:self.pathEditingView.imageGeometryTransform];
    CGContextRef gc = UIGraphicsGetCurrentContext();
    CGContextAddPath(gc, path.CGPath);
    CGContextClip(gc);
    [image drawAtPoint:CGPointZero];
    }];
    }

    它看起来像这样:

    masking demo

    当然,很难说输出图像是全分辨率的。让我们通过将输出图像裁剪到贝塞尔路径的边界框来解决这个问题:
    - (UIImage *)maskedAndCroppedImage {
    UIImage *image = self.pathEditingView.image;
    UIBezierPath *path = [self.pathEditingView.path copy];
    [path applyTransform:self.pathEditingView.imageGeometryTransform];
    CGRect pathBounds = CGPathGetPathBoundingBox(path.CGPath);
    UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init];
    format.scale = image.scale;
    format.prefersExtendedRange = image.imageRendererFormat.prefersExtendedRange;
    format.opaque = NO;
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:pathBounds.size format:format];
    return [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
    CGContextRef gc = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(gc, -pathBounds.origin.x, -pathBounds.origin.y);
    CGContextAddPath(gc, path.CGPath);
    CGContextClip(gc);
    [image drawAtPoint:CGPointZero];
    }];
    }

    掩蔽和裁剪在一起看起来像这样:

    masking and cropping demo

    您可以在此演示中看到,输出图像的细节比在输入 View 中可见的要多得多,因为它是在输入图像的全分辨率下生成的。

    关于ios - 使用具有图像全分辨率的 bezierpath 屏蔽图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48599949/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com