Ios 使用bezierpath和image';完全分辨率
嗨,我有一个路径(形状)和一个高分辨率图像。我将高分辨率图像设置为AspectFit,在绘制路径的视图中,我想用路径遮罩图像,但以图像的全分辨率,而不是以我们看到路径的分辨率。问题是,如果我不将它们放大以获得高分辨率的掩蔽效果,它的效果会非常好,但如果我这样做,一切都会一团糟。面具被拉长了,起源没有意义 我所希望的就是能够以相同的图像纵横比(在图像的全分辨率下)放大路径,并正确定位路径,以便能够正确遮罩高分辨率图像。 我试过这个: 还有这个 还有这个 当我试图遮罩高质量图像(大于屏幕分辨率)时,这些都不能正常工作 编辑我发布了一个工作项目,以显示github上正常质量掩蔽(屏幕分辨率)和高质量掩蔽(图像分辨率)之间的问题。我真的很感激任何帮助。Ios 使用bezierpath和image';完全分辨率,ios,objective-c,uiimage,uibezierpath,cgcontext,Ios,Objective C,Uiimage,Uibezierpath,Cgcontext,嗨,我有一个路径(形状)和一个高分辨率图像。我将高分辨率图像设置为AspectFit,在绘制路径的视图中,我想用路径遮罩图像,但以图像的全分辨率,而不是以我们看到路径的分辨率。问题是,如果我不将它们放大以获得高分辨率的掩蔽效果,它的效果会非常好,但如果我这样做,一切都会一团糟。面具被拉长了,起源没有意义 我所希望的就是能够以相同的图像纵横比(在图像的全分辨率下)放大路径,并正确定位路径,以便能够正确遮罩高分辨率图像。 我试过这个: 还有这个 还有这个 当我试图遮罩高质量图像(大于屏幕分辨
如果我正确理解了您的问题:
- 您有一个包含图像的图像视图,该图像可能已使用
缩小(甚至放大)UIViewContentModeScaleAspectFit
- 您有一个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