将 UIImage 剪辑到 UIBezierPath(不屏蔽)
Clip UIImage to UIBezierPath (not masking)
我正在尝试根据给定的 UIBezierPath
裁剪 UIImage
,但生成的图像保留了原始形状和大小。我希望形状和大小类似于路径,即新图像的可见内容。
看看下面这个例子:
以下是我用来屏蔽给定路径的图像的代码:
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(
width: size.width,
height: size.height
), false, 0.0)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
context.restoreGState()
UIGraphicsEndImageContext()
return newImage
}
一种解决方案是在遮盖图像后对其进行裁剪,但理想情况下,我希望一次性尽可能简单高效地完成此操作。
如有任何解决方案/提示,我们将不胜感激。
感谢 Rob 我能够使用 CGImage
的 cropping(to:)
方法实施解决方案。
这是一个两步过程,首先我使用给定的路径遮盖图像,然后使用路径的边界裁剪结果。
以下是我实现 clipping UIBezierPath
UIImage
扩展的最终工作源代码:
extension UIImage {
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
// Mask image using path
let maskedImage = imageByApplyingMaskingBezierPath(path)
// Crop image to frame of path
let croppedImage = UIImage(cgImage: maskedImage.cgImage!.cropping(to: path.bounds)!)
return croppedImage
}
func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage {
// Define graphic context (canvas) to paint on
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
// Set the clipping mask
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!
// Restore previous drawing context
context.restoreGState()
UIGraphicsEndImageContext()
return maskedImage
}
}
我在 objective C 中使用以下内容将图像裁剪为非透明反应。检查它是否有帮助
@implementation UIImage (cropTransperant)
- (UIImage *) CropimageByTrimmingTransparentPixels {
int rows = self.size.height;
int cols = self.size.width;
int bytesPerRow = cols*sizeof(uint8_t);
if ( rows < 2 || cols < 2 ) {
return self;
}
uint8_t *bitmapData = calloc(rows*cols, sizeof(uint8_t));
CGContextRef contextRef = CGBitmapContextCreate(bitmapData, cols, rows, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
CGImageRef cgImage = self.CGImage;
CGRect rect = CGRectMake(0, 0, cols, rows);
CGContextDrawImage(contextRef, rect, cgImage);
//get all non-transparent pixels in every row and every column
uint16_t *rowSum = calloc(rows, sizeof(uint16_t));
uint16_t *colSum = calloc(cols, sizeof(uint16_t));
//loop through all pixels
for ( int row = 0; row < rows; row++) {
for ( int col = 0; col < cols; col++)
{
if ( bitmapData[row*bytesPerRow + col] ) { //when you get non transperant pixel
rowSum[row]++;
colSum[col]++;
}
}
}
UIEdgeInsets crop = UIEdgeInsetsMake(0, 0, 0, 0); //croprect, initialize with 0,0,0,
for ( int i = 0; i<rows; i++ ) { //get top
if ( rowSum[i] > 0 ) {
crop.top = i; break;
}
}
for ( int i = rows; i >= 0; i-- ) { //get bottom
if ( rowSum[i] > 0 ) {
crop.bottom = MAX(0, rows-i-1); break;
}
}
for ( int i = 0; i<cols; i++ ) { //get left
if ( colSum[i] > 0 ) {
crop.left = i; break;
}
}
for ( int i = cols; i >= 0; i-- ) { //get right
if ( colSum[i] > 0 ) {
crop.right = MAX(0, cols-i-1); break;
}
}
free(bitmapData);
free(colSum);
free(rowSum);
if ( crop.top == 0 && crop.bottom == 0 && crop.left == 0 && crop.right == 0 ) {
return self;
}
else {
rect.origin.x += crop.left;
rect.origin.y += crop.top;
rect.size.width -= crop.left + crop.right;
rect.size.height -= crop.top + crop.bottom;
//crop image to calcualted rect
CGImageRef newImage = CGImageCreateWithImageInRect(cgImage, rect);
return [UIImage imageWithCGImage:newImage];
}
}
@end
我正在尝试根据给定的 UIBezierPath
裁剪 UIImage
,但生成的图像保留了原始形状和大小。我希望形状和大小类似于路径,即新图像的可见内容。
看看下面这个例子:
以下是我用来屏蔽给定路径的图像的代码:
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
UIGraphicsBeginImageContextWithOptions(CGSize(
width: size.width,
height: size.height
), false, 0.0)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
context.restoreGState()
UIGraphicsEndImageContext()
return newImage
}
一种解决方案是在遮盖图像后对其进行裁剪,但理想情况下,我希望一次性尽可能简单高效地完成此操作。
如有任何解决方案/提示,我们将不胜感激。
感谢 Rob 我能够使用 CGImage
的 cropping(to:)
方法实施解决方案。
这是一个两步过程,首先我使用给定的路径遮盖图像,然后使用路径的边界裁剪结果。
以下是我实现 clipping UIBezierPath
UIImage
扩展的最终工作源代码:
extension UIImage {
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
// Mask image using path
let maskedImage = imageByApplyingMaskingBezierPath(path)
// Crop image to frame of path
let croppedImage = UIImage(cgImage: maskedImage.cgImage!.cropping(to: path.bounds)!)
return croppedImage
}
func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage {
// Define graphic context (canvas) to paint on
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
// Set the clipping mask
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!
// Restore previous drawing context
context.restoreGState()
UIGraphicsEndImageContext()
return maskedImage
}
}
我在 objective C 中使用以下内容将图像裁剪为非透明反应。检查它是否有帮助
@implementation UIImage (cropTransperant)
- (UIImage *) CropimageByTrimmingTransparentPixels {
int rows = self.size.height;
int cols = self.size.width;
int bytesPerRow = cols*sizeof(uint8_t);
if ( rows < 2 || cols < 2 ) {
return self;
}
uint8_t *bitmapData = calloc(rows*cols, sizeof(uint8_t));
CGContextRef contextRef = CGBitmapContextCreate(bitmapData, cols, rows, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
CGImageRef cgImage = self.CGImage;
CGRect rect = CGRectMake(0, 0, cols, rows);
CGContextDrawImage(contextRef, rect, cgImage);
//get all non-transparent pixels in every row and every column
uint16_t *rowSum = calloc(rows, sizeof(uint16_t));
uint16_t *colSum = calloc(cols, sizeof(uint16_t));
//loop through all pixels
for ( int row = 0; row < rows; row++) {
for ( int col = 0; col < cols; col++)
{
if ( bitmapData[row*bytesPerRow + col] ) { //when you get non transperant pixel
rowSum[row]++;
colSum[col]++;
}
}
}
UIEdgeInsets crop = UIEdgeInsetsMake(0, 0, 0, 0); //croprect, initialize with 0,0,0,
for ( int i = 0; i<rows; i++ ) { //get top
if ( rowSum[i] > 0 ) {
crop.top = i; break;
}
}
for ( int i = rows; i >= 0; i-- ) { //get bottom
if ( rowSum[i] > 0 ) {
crop.bottom = MAX(0, rows-i-1); break;
}
}
for ( int i = 0; i<cols; i++ ) { //get left
if ( colSum[i] > 0 ) {
crop.left = i; break;
}
}
for ( int i = cols; i >= 0; i-- ) { //get right
if ( colSum[i] > 0 ) {
crop.right = MAX(0, cols-i-1); break;
}
}
free(bitmapData);
free(colSum);
free(rowSum);
if ( crop.top == 0 && crop.bottom == 0 && crop.left == 0 && crop.right == 0 ) {
return self;
}
else {
rect.origin.x += crop.left;
rect.origin.y += crop.top;
rect.size.width -= crop.left + crop.right;
rect.size.height -= crop.top + crop.bottom;
//crop image to calcualted rect
CGImageRef newImage = CGImageCreateWithImageInRect(cgImage, rect);
return [UIImage imageWithCGImage:newImage];
}
}
@end