2016-11-26 4 views
2

UIBezierPathに基づいてUIImageをクリップしようとしましたが、結果のイメージは元の形とサイズを保持します。シェイプとサイズをパス、つまり新しい画像の表示内容に似せてください。UIBezierPathにUIBezierPathをクリップする(マスキングしない)

この次の例を見てみましょう:

Input image, input path, actual result, and desired result

次は、私はパス指定した画像をマスクするために使用していたコードです:

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 
} 

一つの解決策は、作物になりますそれをマスキングした後の画像ですが、理想的には、これを可能な限りシンプルかつ効率的に実行したいと考えています。

解決方法やヒントがあれば幸いです。

+1

いいえ、ちょうどそれを切り抜いてください。しかし、CGImageCreateWithImageInRectを1回呼び出すだけで、とても簡単です。 – Rob

+0

コメントをいただきありがとう@Rob、これを実装する方法についての素早いコードスニペットをお伝えしますか? – Aleksander

+0

コーディングサンプルRobの必要がなくなりました。ポインタありがとう! – Aleksander

答えて

3

Robのおかげで、メソッドを使用してCGImageのソリューションを実装することができました。

これは、指定されたパスを使用してイメージをマスクし、パスの境界を使用して結果をトリミングする2段階のプロセスです。私は非transperant RECTに任意の画像をトリミングするために、客観Cで、次の使用しています

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 
    } 

} 
+0

偉大な仕事! man〜 – Jerome

+0

以下の目的のCバージョンは、ソリューションのクロッピング部分のみを表示します。すべてのソリューションの完全な目的のCバージョンを使用できる可能性があります。 @アレクサンダー私は本当にそれを感謝したい。 –

0

次はクリッピングUIBezierPathUIImage拡張を実装するための私の最後の作業のソースコードです。役立つかどうかを確認してください。

@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 
+0

私はコードをテストする機会はありませんでしたが、理にかなっているようです。しかし、理想的には私はより簡単で効率的なソリューションを探していました。私はそれがなぜ投票されたのか分からない、誰も説明する気がない? – Aleksander