2013-05-15 10 views
5

透き通った背景を持つUIImageを取って、可視の画像データだけが残るようにクロップする最小の矩形を決める戦略は何ですか?データは長方形ではありません)透明な背景を持つUIImageのクロップ矩形を検出する

私は、UIImageをCGRectにクロップするための多くの情報、ユーザーの介入が必要なクロップビューコントローラ、画像処理クラスとカテゴリ(MGImageUtilitiesとNYXImagesKitを含む)を持ついくつかのオープンソースライブラリを見つけましたが、私の特別な問題を解決します。

私の現在のアプリはiOS 5.0をターゲットにしているため、そのアプリとの互換性は最適です。

EDIT:エッジ境界を探している行と列の画像データの最悪のシナリオでは、すべてのピクセルを見てブルートフォースよりも良い方法があることを望んでいます。

答えて

9

https://gist.github.com/spinogrizz/3549921を見たことがありますか?

これはまさにあなたが必要としているようです。それは、そのページからコピーペースト&失われていないだけので

- (UIImage *) imageByTrimmingTransparentPixels { 
    int rows = self.size.height; 
    int cols = self.size.width; 
    int bytesPerRow = cols*sizeof(uint8_t); 

    if (rows < 2 || cols < 2) { 
     return self; 
    } 

    //allocate array to hold alpha channel 
    uint8_t *bitmapData = calloc(rows*cols, sizeof(uint8_t)); 

    //create alpha-only bitmap context 
    CGContextRef contextRef = CGBitmapContextCreate(bitmapData, cols, rows, 8, bytesPerRow, NULL, kCGImageAlphaOnly); 

    //draw our image on that context 
    CGImageRef cgImage = self.CGImage; 
    CGRect rect = CGRectMake(0, 0, cols, rows); 
    CGContextDrawImage(contextRef, rect, cgImage); 

    //summ 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)); 

    //enumerate through all pixels 
    for (int row = 0; row < rows; row++) { 
     for (int col = 0; col < cols; col++) 
     { 
      if (bitmapData[row*bytesPerRow + col]) { //found non-transparent pixel 
       rowSum[row]++; 
       colSum[col]++; 
      } 
     } 
    } 

    //initialize crop insets and enumerate cols/rows arrays until we find non-empty columns or row 
    UIEdgeInsets crop = UIEdgeInsetsMake(0, 0, 0, 0); 

    for (int i = 0; i<rows; i++) {  //top 
     if (rowSum[i] > 0) { 
      crop.top = i; break; 
     } 
    } 

    for (int i = rows; i >= 0; i--) {  //bottom 
     if (rowSum[i] > 0) { 
      crop.bottom = MAX(0, rows-i-1); break; 
     } 
    } 

    for (int i = 0; i<cols; i++) {  //left 
     if (colSum[i] > 0) { 
      crop.left = i; break; 
     } 
    } 

    for (int i = cols; i >= 0; i--) {  //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) { 
     //no cropping needed 
     return self; 
    } 
    else { 
     //calculate new crop bounds 
     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 it 
     CGImageRef newImage = CGImageCreateWithImageInRect(cgImage, rect); 

     //convert back to UIImage 
     return [UIImage imageWithCGImage:newImage]; 
    } 
} 
+0

スウィフト4であるが、それは十分に機能します。ありがとう。 –

+0

私のために働きました(Y) – Xeieshan

+1

私のために働いていませんが、うまくいけば別のバージョンが浮かんでいます... – Benjohn

-5

はWWDCでCoreImageスライドを参照してください。 あなたの答えは直接です。

0

は、ここではそれはそれは少し醜いです

extension UIImage { 

func cropAlpha() -> UIImage { 

    let cgImage = self.cgImage!; 

    let width = cgImage.width 
    let height = cgImage.height 

    let colorSpace = CGColorSpaceCreateDeviceRGB() 
    let bytesPerPixel:Int = 4 
    let bytesPerRow = bytesPerPixel * width 
    let bitsPerComponent = 8 
    let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue 

    guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo), 
     let ptr = context.data?.assumingMemoryBound(to: UInt8.self) else { 
      return self 
    } 

    context.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: width, height: height)) 

    var minX = width 
    var minY = height 
    var maxX: Int = 0 
    var maxY: Int = 0 

    for x in 1 ..< width { 
     for y in 1 ..< height { 

      let i = bytesPerRow * Int(y) + bytesPerPixel * Int(x) 
      let a = CGFloat(ptr[i + 3])/255.0 

      if(a>0) { 
       if (x < minX) { minX = x }; 
       if (x > maxX) { maxX = x }; 
       if (y < minY) { minY = y}; 
       if (y > maxY) { maxY = y}; 
      } 
     } 
    } 

    let rect = CGRect(x: CGFloat(minX),y: CGFloat(minY), width: CGFloat(maxX-minX), height: CGFloat(maxY-minY)) 
    let imageScale:CGFloat = self.scale 
    let croppedImage = self.cgImage!.cropping(to: rect)! 
    let ret = UIImage(cgImage: croppedImage, scale: imageScale, orientation: self.imageOrientation) 

    return ret; 
} 

}