Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用bezierpath和image';完全分辨率_Ios_Objective C_Uiimage_Uibezierpath_Cgcontext - Fatal编程技术网

Ios 使用bezierpath和image';完全分辨率

Ios 使用bezierpath和image';完全分辨率,ios,objective-c,uiimage,uibezierpath,cgcontext,Ios,Objective C,Uiimage,Uibezierpath,Cgcontext,嗨,我有一个路径(形状)和一个高分辨率图像。我将高分辨率图像设置为AspectFit,在绘制路径的视图中,我想用路径遮罩图像,但以图像的全分辨率,而不是以我们看到路径的分辨率。问题是,如果我不将它们放大以获得高分辨率的掩蔽效果,它的效果会非常好,但如果我这样做,一切都会一团糟。面具被拉长了,起源没有意义 我所希望的就是能够以相同的图像纵横比(在图像的全分辨率下)放大路径,并正确定位路径,以便能够正确遮罩高分辨率图像。 我试过这个: 还有这个 还有这个 当我试图遮罩高质量图像(大于屏幕分辨

嗨,我有一个路径(形状)和一个高分辨率图像。我将高分辨率图像设置为AspectFit,在绘制路径的视图中,我想用路径遮罩图像,但以图像的全分辨率,而不是以我们看到路径的分辨率。问题是,如果我不将它们放大以获得高分辨率的掩蔽效果,它的效果会非常好,但如果我这样做,一切都会一团糟。面具被拉长了,起源没有意义

我所希望的就是能够以相同的图像纵横比(在图像的全分辨率下)放大路径,并正确定位路径,以便能够正确遮罩高分辨率图像。 我试过这个:

还有这个

还有这个

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

编辑我发布了一个工作项目,以显示github上正常质量掩蔽(屏幕分辨率)和高质量掩蔽(图像分辨率)之间的问题。我真的很感激任何帮助。

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

  • 您有一个包含图像的图像视图,该图像可能已使用
    UIViewContentModeScaleAspectFit
    缩小(甚至放大)
  • 您有一个bezier路径,其点位于该图像视图的几何体(坐标系)中
现在,您需要创建图像的副本,以其原始分辨率,由贝塞尔路径遮罩

我们可以将图像视为具有自己的几何体,原点位于图像的左上角,沿每个轴的一个单位为一个点。因此,我们需要做的是:

  • 创建一个足够大的图形渲染器,以便在不缩放的情况下将图像绘制到其中。此渲染器的几何体是图像的几何体
  • 将bezier路径从视图几何体转换为渲染器几何体
  • 将变换后的路径应用于渲染器的剪辑区域
  • 将图像(未转换)绘制到渲染器中
  • 第二步很难,因为我们必须找到正确的
    CGAffineTransform
    。在aspect fit场景中,变换不仅需要缩放图像,还可能沿x轴或y轴(但不能同时沿x轴和y轴)平移图像。但是,让我们更一般地支持其他
    UIViewContentMode
    设置。下面是一个类别,您可以向
    UIImageView
    询问将视图几何体中的点转换为图像几何体中的点的变换:

    @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
    
    看起来是这样的:

    - (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];
        }];
    }
    

    当然,很难说输出的图像是全分辨率的。让我们通过将输出图像裁剪到bezier路径的边界框来修复此问题:

    - (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];
        }];
    }
    
    遮罩和裁剪一起看起来如下所示:

    - (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];
        }];
    }
    


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

    作为第二个答案,我将其与此代码配合使用,以便更好地理解,您也可以在这里获得github上的工作项目,看看它是否适用于所有情况。 我的github项目:

    解决问题的代码部分:

    -(UIImage*)highResolutionMasking{
        NSLog(@"///High quality (Image resolution) masking///////////////////////////////////////////////////");
    
        //1.Rendering the path into an image with the size of _targetBound (which is the size of a device screen sized view in which the path is drawn.)
        CGFloat aspectRatioOfImageBasedOnHeight = _highResolutionImage.size.height/ _highResolutionImage.size.width;
        CGFloat aspectRatioOfTargetBoundBasedOnHeight = _targetBound.size.height/ _targetBound.size.width;
    
        CGFloat pathScalingFactor = 0;
        if ((_highResolutionImage.size.height >= _targetBound.size.height)||
            (_highResolutionImage.size.width  >= _targetBound.size.width)) {
                //Then image is bigger than targetBound
    
                if ((_highResolutionImage.size.height<=_highResolutionImage.size.width)) {
                //The image is Horizontal
    
                    CGFloat newWidthForTargetBound =_highResolutionImage.size.width;
                    CGFloat ratioOfHighresImgWidthToTargetBoundWidth = (_highResolutionImage.size.width/_targetBound.size.width);
                    CGFloat newHeightForTargetBound = _targetBound.size.height* ratioOfHighresImgWidthToTargetBoundWidth;
    
                    _bigTargetBound = CGRectMake(0, 0, newWidthForTargetBound, newHeightForTargetBound);
                    pathScalingFactor = _highResolutionImage.size.width/_targetBound.size.width;
    
                }else if((_highResolutionImage.size.height > _highResolutionImage.size.width)&&
                         (aspectRatioOfImageBasedOnHeight  <= aspectRatioOfTargetBoundBasedOnHeight)){
                    //The image is Vertical but has smaller aspect ratio (based on height) than targetBound
    
                    CGFloat newWidthForTargetBound =_highResolutionImage.size.width;
                    CGFloat ratioOfHighresImgWidthToTargetBoundWidth = (_highResolutionImage.size.width/_targetBound.size.width);
                    CGFloat newHeightForTargetBound = _targetBound.size.height* ratioOfHighresImgWidthToTargetBoundWidth;
    
                    _bigTargetBound = CGRectMake(0, 0, newWidthForTargetBound, newHeightForTargetBound);
                    pathScalingFactor = _highResolutionImage.size.width/_targetBound.size.width;
    
                }else if((_highResolutionImage.size.height > _highResolutionImage.size.width)&&
                         (aspectRatioOfImageBasedOnHeight  > aspectRatioOfTargetBoundBasedOnHeight)){
    
                    CGFloat newHeightForTargetBound =_highResolutionImage.size.height;
                    CGFloat ratioOfHighresImgHeightToTargetBoundHeight = (_highResolutionImage.size.height/_targetBound.size.height);
                    CGFloat newWidthForTargetBound = _targetBound.size.width* ratioOfHighresImgHeightToTargetBoundHeight;
    
                    _bigTargetBound = CGRectMake(0, 0, newWidthForTargetBound, newHeightForTargetBound);
                    pathScalingFactor = _highResolutionImage.size.height/_targetBound.size.height;
                }else{
                    //Do nothing
                }
        }else{
                //Then image is smaller than targetBound
                _bigTargetBound = _imageRect;
                pathScalingFactor =1;
        }
    
        CGSize correctedSize = CGSizeMake(_highResolutionImage.size.width  *_scale,
                                          _highResolutionImage.size.height *_scale);
    
        _bigImageRect= AVMakeRectWithAspectRatioInsideRect(correctedSize,_bigTargetBound);
    
        //Scaling path
        CGAffineTransform scaleTransform = CGAffineTransformIdentity;
        scaleTransform = CGAffineTransformScale(scaleTransform, pathScalingFactor, pathScalingFactor);
    
        CGPathRef scaledCGPath = CGPathCreateCopyByTransformingPath(_examplePath.CGPath,&scaleTransform);
    
        //Render scaled path into image
        UIGraphicsBeginImageContextWithOptions(_bigTargetBound.size, NO, 1.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextAddPath (context, scaledCGPath);
        CGContextSetFillColorWithColor (context, [UIColor redColor].CGColor);
        CGContextSetStrokeColorWithColor (context, [UIColor redColor].CGColor);
        CGContextDrawPath (context, kCGPathFillStroke);
        UIImage * pathImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        NSLog(@"High res pathImage.size: %@",NSStringFromCGSize(pathImage.size));
    
        //Cropping it from targetBound into imageRect
        _maskImage = [self cropThisImage:pathImage toRect:_bigImageRect];
        NSLog(@"High res _croppedRenderedPathImage.size: %@",NSStringFromCGSize(_maskImage.size));
    
        //Masking the high res image with my mask image which both have the same size now.
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGImageRef maskImageRef = [_maskImage CGImage];
        CGContextRef myContext = CGBitmapContextCreate (NULL, _highResolutionImage.size.width, _highResolutionImage.size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(colorSpace);
        if (myContext==NULL)
            return NULL;
    
        CGFloat ratio = 0;
        ratio = _maskImage.size.width/ _highResolutionImage.size.width;
        if(ratio * _highResolutionImage.size.height < _maskImage.size.height) {
            ratio = _maskImage.size.height/ _highResolutionImage.size.height;
        }
    
        CGRect rectForMask  = {{0, 0}, {_maskImage.size.width, _maskImage.size.height}};
        CGRect rectForImageDrawing  = {{-((_highResolutionImage.size.width*ratio)-_maskImage.size.width)/2 , -((_highResolutionImage.size.height*ratio)-_maskImage.size.height)/2},
            {_highResolutionImage.size.width*ratio, _highResolutionImage.size.height*ratio}};
    
        CGContextClipToMask(myContext, rectForMask, maskImageRef);
        CGContextDrawImage(myContext, rectForImageDrawing, _highResolutionImage.CGImage);
        CGImageRef newImage = CGBitmapContextCreateImage(myContext);
        CGContextRelease(myContext);
        UIImage *theImage = [UIImage imageWithCGImage:newImage];
        CGImageRelease(newImage);
        return theImage;
    }
    
    -(UIImage *)cropThisImage:(UIImage*)image toRect:(CGRect)rect{
        CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
        UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
        CGImageRelease(subImage);
        return croppedImage;
    }
    
    -(UIImage*)高分辨率任务{
    NSLog(@/////高质量(图像分辨率)遮罩////////////;
    //1.将路径渲染为大小为_targetBound(即绘制路径的设备屏幕大小视图的大小)的图像
    CGFloat aspectratiofimagebasedonheight=\u highResolutionImage.size.height/\u highResolutionImage.size.width;
    CGFloat aspectratioftargetboundbasedonheight=\u targetBound.size.height/\u targetBound.size.width;
    CGFloat路径缩放因子=0;
    如果(_highResolutionImage.size.height>=\u targetBound.size.height)||
    (\u highResolutionImage.size.width>=\u targetBound.size.width)){
    //然后图像比targetBound大
    if(_highResolutionImage.size.height _highResolutionImage.size.width)&&
    (AspectRatioOfImageBasedOn高度_高分辨率图像大小宽度)&&
    (aspectRatioOfImageBasedOnHeight>aspectRatioOfTargetBoundBasedOnHeight)){
    CGFloat新高度FORTARGETBOND=\u高分辨率图像.size.height;
    CGFloat RATIOOFHIGHRESIMGHIGHTTOTARGETBOUNDHEIGHT=(\u highResolutionImage.size.height/\u targetBound.size.height/\u targetBound);
    CGFloat newWidthForTargetBound=_targetBound.size.width*RatioofHighresightToTargetBoundHeight;
    _bigTargetBound=CGRectMake(0,0,newWidthForTargetBound,newHeightForTargetBound);
    pathScalingFactor=\u highResolutionImage.size.height//\u targetBound.size.height;
    }否则{
    //无所事事
    }
    }否则{
    //然后图像比targetBound小
    _bigTargetBound=_imageRect;
    路径缩放因子=1;
    }
    CGSize correctedSize=CGSizeMake(_highResolutionImage.size.width*_scale,
    _高分辨率图像、大小、高度*_刻度);
    _bigImageRect=AVMakeCrectWithAspectRatioInSideRect(校正大小,_bigTargetBound);
    //缩放路径
    CGAffineTransform scaleTransform=CGAffineTransform一致性;
    scaleTransform=CGAffineTransformScale(scaleTransform、pathScalingFactor、pathScalingFactor);
    CGPathRef scaledCGPath=CGPathCreateCopyByTransformingPath(\u examplePath.CGPath,&scaleTransform);
    //将缩放路径渲染为图像
    UIGraphicsBeginImageContextWithOptions(_bigTargetBound.size,NO,1.0);
    CGContextRef context=UIGraphicsGetCurrentContext();
    CGContextAddPath(上下文,scaledCGPath);
    CGContextSetFillColorWithColor(上下文[UIColor REDCLOR].CGColor);
    CGContextSetStrokeColorWithColor(上下文[UIColor redColor].CGColor);
    CG