-
-
Save AdamLantz/d5d841e60583e740c0b5f515ba5064fb to your computer and use it in GitHub Desktop.
//Swift 4 modifications for this gist: https://gist.github.com/krooked/9c4c81557fc85bc61e51c0b4f3301e6e | |
import Foundation | |
import UIKit | |
extension UIImage { | |
func cropImageByAlpha() -> UIImage { | |
let cgImage = self.cgImage | |
let context = createARGBBitmapContextFromImage(inImage: cgImage!) | |
let height = cgImage!.height | |
let width = cgImage!.width | |
var rect: CGRect = CGRect(x: 0, y: 0, width: CGFloat(width), height: CGFloat(height)) | |
context?.draw(cgImage!, in: rect) | |
let pixelData = self.cgImage!.dataProvider!.data | |
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData) | |
var minX = width | |
var minY = height | |
var maxX: Int = 0 | |
var maxY: Int = 0 | |
//Filter through data and look for non-transparent pixels. | |
for y in 0..<height { | |
for x in 0..<width { | |
let pixelIndex = (width * y + x) * 4 /* 4 for A, R, G, B */ | |
if data[Int(pixelIndex)] != 0 { //Alpha value is not zero pixel is not transparent. | |
if (x < minX) { | |
minX = x | |
} | |
if (x > maxX) { | |
maxX = x | |
} | |
if (y < minY) { | |
minY = y | |
} | |
if (y > maxY) { | |
maxY = y | |
} | |
} | |
} | |
} | |
rect = CGRect( x: CGFloat(minX), y: CGFloat(minY), width: CGFloat(maxX-minX), height: CGFloat(maxY-minY)) | |
let imageScale:CGFloat = self.scale | |
let cgiImage = self.cgImage?.cropping(to: rect) | |
return UIImage(cgImage: cgiImage!, scale: imageScale, orientation: self.imageOrientation) | |
} | |
private func createARGBBitmapContextFromImage(inImage: CGImage) -> CGContext? { | |
let width = cgImage!.width | |
let height = cgImage!.height | |
let bitmapBytesPerRow = width * 4 | |
let bitmapByteCount = bitmapBytesPerRow * height | |
let colorSpace = CGColorSpaceCreateDeviceRGB() | |
if colorSpace == nil { | |
return nil | |
} | |
let bitmapData = malloc(bitmapByteCount) | |
if bitmapData == nil { | |
return nil | |
} | |
let context = CGContext (data: bitmapData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bitmapBytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue) | |
return context | |
} | |
} |
some square particles seen in whole image, like blurry rectangle image. @AdamLantz , Do you feel like same in output image created by your above code?
Should you be looking for a solution for NSImage (macOS): https://github.com/mipmip/NSImage-Trim/blob/master/Pod/Classes/NSImage%2BTrim.m
Great work, thank you so much
Awesome work! But, there's a little catch here.
On line 13, you are drawing the cgImage to the cgContext:
context?.draw(cgImage!, in: rect)
But on line 15, the pixelData comes from the cgImage, instead of what's in the cgContext:
let pixelData = self.cgImage!.dataProvider!.data
The issue with this is that the ARGB order is no longer guaranteed.
I suggest the following edit for lines 15-16:
let redrawnCGImage = context.makeImage()
let pixelData = redrawnCGImage!.dataProvider!.data
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
How can we do the same thing using metal?
Awesome work! But, there's a little catch here.
On line 13, you are drawing the cgImage to the cgContext:
context?.draw(cgImage!, in: rect)
But on line 15, the pixelData comes from the cgImage, instead of what's in the cgContext:
let pixelData = self.cgImage!.dataProvider!.data
The issue with this is that the ARGB order is no longer guaranteed.I suggest the following edit for lines 15-16:
let redrawnCGImage = context.makeImage() let pixelData = redrawnCGImage!.dataProvider!.data let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
Excellent brother... Solved my problem
I tried the above edits, but found in practice only the first crop was correct. Any subsequent crops actually returned (almost) the entire image.
I think I will end up going with this solution: https://stackoverflow.com/a/48759198/883413
thank you
Based upon this gist targeting an older version of Swift:
https://gist.github.com/krooked/9c4c81557fc85bc61e51c0b4f3301e6e