Ios 如何自动录制UIImage?

Ios 如何自动录制UIImage?,ios,cocoa-touch,uikit,uiimage,core-graphics,Ios,Cocoa Touch,Uikit,Uiimage,Core Graphics,我有一个包含形状的UIImage;其余部分是透明的。我希望通过裁剪出尽可能多的透明部分来获得另一个UIImage,同时保留所有的非透明像素-类似于GIMP中的autocrop函数。我该怎么做呢?这种方法可能比你希望的更具侵入性,但它完成了任务。我正在做的是为UIImage创建位图上下文,获取指向原始图像数据的指针,然后在其中筛选非透明像素。我的方法返回用于创建新UIImage的CGRect - (CGRect)cropRectForImage:(UIImage *)image { CGImag

我有一个包含形状的UIImage;其余部分是透明的。我希望通过裁剪出尽可能多的透明部分来获得另一个UIImage,同时保留所有的非透明像素-类似于GIMP中的autocrop函数。我该怎么做呢?

这种方法可能比你希望的更具侵入性,但它完成了任务。我正在做的是为UIImage创建位图上下文,获取指向原始图像数据的指针,然后在其中筛选非透明像素。我的方法返回用于创建新UIImage的CGRect

- (CGRect)cropRectForImage:(UIImage *)image {

CGImageRef cgImage = image.CGImage;
CGContextRef context = [self createARGBBitmapContextFromImage:cgImage];
if (context == NULL) return CGRectZero; 

size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
CGRect rect = CGRectMake(0, 0, width, height);

CGContextDrawImage(context, rect, cgImage);

unsigned char *data = CGBitmapContextGetData(context);
CGContextRelease(context);

//Filter through data and look for non-transparent pixels.
int lowX = width;
int lowY = height;
int highX = 0;
int highY = 0;
if (data != NULL) {
    for (int y=0; y<height; y++) {
        for (int x=0; x<width; x++) {
            int pixelIndex = (width * y + x) * 4 /* 4 for A, R, G, B */;
            if (data[pixelIndex] != 0) { //Alpha value is not zero; pixel is not transparent.
                if (x < lowX) lowX = x;
                if (x > highX) highX = x;
                if (y < lowY) lowY = y;
                if (y > highY) highY = y;
            }
        }
    }
    free(data);
} else {
    return CGRectZero;
}

return CGRectMake(lowX, lowY, highX-lowX, highY-lowY);
}
最后,从返回的CGRect获取新裁剪的UIImage:

CGRect newRect = [self cropRectForImage:oldImage];
CGImageRef imageRef = CGImageCreateWithImageInRect(oldImage.CGImage, newRect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
let image = // UIImage Source
let newRect = image.cropRect()
if let imageRef = CGImageCreateWithImageInRect(image.CGImage!, newRect) {
    let newImage = UIImage(CGImage: imageRef)
    // Use this new Image
}

我从你的电脑上抓到了一点代码。希望有帮助

Swift版本:

extension UIImage {
func cropRect() -> CGRect {
    let cgImage = self.CGImage!
    let context = createARGBBitmapContextFromImage(cgImage)
    if context == nil {
        return CGRectZero
    }

    let height = CGFloat(CGImageGetHeight(cgImage))
    let width = CGFloat(CGImageGetWidth(cgImage))

    let rect = CGRectMake(0, 0, width, height)
    CGContextDrawImage(context, rect, cgImage)

    let data = UnsafePointer<CUnsignedChar>(CGBitmapContextGetData(context))

    if data == nil {
        return CGRectZero
    }

    var lowX = width
    var lowY = height
    var highX: CGFloat = 0
    var highY: CGFloat = 0

    //Filter through data and look for non-transparent pixels.
    for (var y: CGFloat = 0 ; y < height ; y++) {
        for (var x: CGFloat = 0; x < width ; x++) {
            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 < lowX) {
                    lowX = x
                }
                if (x > highX) {
                    highX = x
                }
                if (y < lowY) {
                    lowY = y
                }
                if (y > highY) {
                    highY = y
                }
            }
        }
    }


    return CGRectMake(lowX, lowY, highX-lowX, highY-lowY)
}
}
最后,从返回的CGRect获取新裁剪的UIImage:

CGRect newRect = [self cropRectForImage:oldImage];
CGImageRef imageRef = CGImageCreateWithImageInRect(oldImage.CGImage, newRect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
let image = // UIImage Source
let newRect = image.cropRect()
if let imageRef = CGImageCreateWithImageInRect(image.CGImage!, newRect) {
    let newImage = UIImage(CGImage: imageRef)
    // Use this new Image
}
Swift 3(它不是UIImage扩展,我在另一门课上需要它)它可能会为某人节省时间:

class EditImage {

static func cropRect(_ image: UIImage) -> CGRect {
    let cgImage = image.cgImage
    let context = createARGBBitmapContextFromImage(inImage: cgImage!)
    if context == nil {
        return CGRect.zero
    }

    let height = CGFloat(cgImage!.height)
    let width = CGFloat(cgImage!.width)

    let rect = CGRect(x: 0, y: 0, width: width, height: height)
    context?.draw(cgImage!, in: rect)

    //let data = UnsafePointer<CUnsignedChar>(CGBitmapContextGetData(context))
    let data = context?.data?.assumingMemoryBound(to: UInt8.self)

    if data == nil {
        return CGRect.zero
    }

    var lowX = width
    var lowY = height
    var highX: CGFloat = 0
    var highY: CGFloat = 0

    let heightInt = Int(height)
    let widthInt = Int(width)
    //Filter through data and look for non-transparent pixels.
    for y in (0 ..< heightInt) {
        let y = CGFloat(y)
        for x in (0 ..< widthInt) {
            let x = CGFloat(x)
            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 < lowX) {
                    lowX = x
                }
                if (x > highX) {
                    highX = x
                }
                if (y < lowY) {
                    lowY = y
                }
                if (y > highY) {
                    highY = y
                }
            }
        }
    }


    return CGRect(x: lowX, y: lowY, width: highX - lowY, height: highY - lowY)
}

static func createARGBBitmapContextFromImage(inImage: CGImage) -> CGContext? {

    let width = inImage.width
    let height = inImage.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,      // bits per component
        bytesPerRow: bitmapBytesPerRow,
        space: colorSpace,
    bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)

    return context
}
}
class编辑图像{
静态函数cropRect(image:UIImage)->CGRect{
设cgImage=image.cgImage
让context=createARGBBitmapContextFromImage(inImage:cgImage!)
如果上下文==nil{
返回CGRect.zero
}
let height=CGFloat(cgImage!.height)
让宽度=CGFloat(cgImage!.width)
设rect=CGRect(x:0,y:0,宽度:宽度,高度:高度)
上下文?.draw(cgImage!,in:rect)
//let data=UnsafePointer(CGBitmapContextGetData(上下文))
让数据=上下文?.data?.AssumingMemoryBind(到:UInt8.self)
如果数据==nil{
返回CGRect.zero
}
var lowX=宽度
var lowY=高度
var highX:CGFloat=0
变量高:CGFloat=0
let heightInt=Int(高度)
设widthInt=Int(宽度)
//过滤数据并查找不透明像素。
对于y英寸(0..<高度){
设y=CGFloat(y)
对于x英寸(0..高x){
高x=x
}
if(y高){
highY=y
}
}
}
}
返回CGRect(x:lowX,y:lowY,宽度:highX-lowY,高度:highY-lowY)
}
静态函数createARGBBitmapContextFromImage(inImage:CGImage)->CGContext{
让宽度=inImage.width
让高度=图像高度
让bitmapBytesPerRow=宽度*4
设bitmapByteCount=bitmapBytesPerRow*高度
让colorSpace=CGColorSpaceCreateDeviceRGB()
如果颜色空间==nil{
归零
}
让bitmapData=malloc(bitmapByteCount)
如果bitmapData==nil{
归零
}
让context=CGContext(数据:bitmapData,
宽度:宽度,
高度:高度,,
bitsPerComponent:8,每个组件//位
bytesPerRow:bitmapBytesPerRow,
空间:色彩空间,
bitmapInfo:CGImageAlphaInfo.PremultipledFirst.rawValue)
返回上下文
}
}

改进了@Danny182的答案,我还根据自己的需要添加了空白(任何比0xe0亮的像素)

用法:

let newimage = UIImage(named: "XXX")!.trim()

导入UIKit
扩展UIImage{
func trim()->UIImage{
设newRect=self.cropRect
如果让imageRef=self.cgImage!。裁剪(到:newRect){
返回UIImage(cgImage:imageRef)
}
回归自我
}
变量cropRect:CGRect{
设cgImage=self.cgImage
让context=createARGBBitmapContextFromImage(inImage:cgImage!)
如果上下文==nil{
返回CGRect.zero
}
let height=CGFloat(cgImage!.height)
让宽度=CGFloat(cgImage!.width)
设rect=CGRect(x:0,y:0,宽度:宽度,高度:高度)
上下文?.draw(cgImage!,in:rect)
//let data=UnsafePointer(CGBitmapContextGetData(上下文))
guard let data=context?.data?.AssumingMemoryBind(到:UInt8.self)else{
返回CGRect.zero
}
var lowX=宽度
var lowY=高度
var highX:CGFloat=0
变量高:CGFloat=0
let heightInt=Int(高度)
设widthInt=Int(宽度)
//过滤数据并查找不透明像素。
对于y英寸(0..<高度){
设y=CGFloat(y)
对于x英寸(0..0xE0和数据[Int(像素索引+2)]>0xE0和数据[Int(像素索引+3)]>0xE0{continue}//裁剪为白色
if(x高x){
高x=x
}
if(y高){
highY=y
}
}
}
返回CGRect(x:lowX,y:lowY,宽度:highX-lowX,高度:highY-lowY)
}
func createARGBBitmapContextFromImage(inImage:CGImage)->CGContext{
让宽度=inImage.width
让高度=图像高度
让bitmapBytesPerRow=宽度*4
设bitmapByteCount=bitmapBytesPerRow*高度
让colorSpace=CGColorSpaceCreateDeviceRGB()
让bitmapData=malloc(bitmapByteCount)
如果bitmapData==nil{
归零
}
让context=CGContext(数据:bitmapData,
宽度:宽度,
高度:高度
import UIKit

extension UIImage {

    func trim() -> UIImage {
        let newRect = self.cropRect
        if let imageRef = self.cgImage!.cropping(to: newRect) {
            return UIImage(cgImage: imageRef)
        }
        return self
    }

    var cropRect: CGRect {
        let cgImage = self.cgImage
        let context = createARGBBitmapContextFromImage(inImage: cgImage!)
        if context == nil {
            return CGRect.zero
        }

        let height = CGFloat(cgImage!.height)
        let width = CGFloat(cgImage!.width)

        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        context?.draw(cgImage!, in: rect)

        //let data = UnsafePointer<CUnsignedChar>(CGBitmapContextGetData(context))
        guard let data = context?.data?.assumingMemoryBound(to: UInt8.self) else {
            return CGRect.zero
        }

        var lowX = width
        var lowY = height
        var highX: CGFloat = 0
        var highY: CGFloat = 0

        let heightInt = Int(height)
        let widthInt = Int(width)
        //Filter through data and look for non-transparent pixels.
        for y in (0 ..< heightInt) {
            let y = CGFloat(y)
            for x in (0 ..< widthInt) {
                let x = CGFloat(x)
                let pixelIndex = (width * y + x) * 4 /* 4 for A, R, G, B */

                if data[Int(pixelIndex)] == 0  { continue } // crop transparent

                if data[Int(pixelIndex+1)] > 0xE0 && data[Int(pixelIndex+2)] > 0xE0 && data[Int(pixelIndex+3)] > 0xE0 { continue } // crop white

                if (x < lowX) {
                    lowX = x
                }
                if (x > highX) {
                    highX = x
                }
                if (y < lowY) {
                    lowY = y
                }
                if (y > highY) {
                    highY = y
                }

            }
        }

        return CGRect(x: lowX, y: lowY, width: highX - lowX, height: highY - lowY)
    }

    func createARGBBitmapContextFromImage(inImage: CGImage) -> CGContext? {

        let width = inImage.width
        let height = inImage.height

        let bitmapBytesPerRow = width * 4
        let bitmapByteCount = bitmapBytesPerRow * height

        let colorSpace = CGColorSpaceCreateDeviceRGB()

        let bitmapData = malloc(bitmapByteCount)
        if bitmapData == nil {
            return nil
        }

        let context = CGContext (data: bitmapData,
                                 width: width,
                                 height: height,
                                 bitsPerComponent: 8,      // bits per component
            bytesPerRow: bitmapBytesPerRow,
            space: colorSpace,
            bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)

        return context
    }
}
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;
    }
    
}
func cropRect() -> CGRect {
    let cgImage = self.cgImage!

    let bitmapBytesPerRow = cgImage.width * 4
    let bitmapByteCount = bitmapBytesPerRow * cgImage.height
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapData = malloc(bitmapByteCount)

    if bitmapData == nil {
        return CGRect(x: 0, y: 0, width: 0, height: 0)
    }

    let context = CGContext (data: bitmapData, width: cgImage.width, height: cgImage.height, bitsPerComponent: 8,bytesPerRow: bitmapBytesPerRow,space: colorSpace,bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)

    if context == nil {
        return CGRect(x: 0, y: 0, width: 0, height: 0)
    }

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

    let rect = CGRect(x: 0, y: 0, width: width, height: height)
    context?.clear(rect)
    context?.draw(cgImage, in: rect)

    let data = context?.data

    if data == nil {
        return CGRect(x: 0, y: 0, width: 0, height: 0)
    }

    var lowX = width
    var lowY = height
    var highX: Int = 0
    var highY: 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 */
            let color = data!.load(fromByteOffset: pixelIndex, as: UInt32.self)

            if color != 0 { //Alpha value is not zero pixel is not transparent.
                if (x < lowX) {
                    lowX = x
                }
                if (x > highX) {
                    highX = x
                }
                if (y < lowY) {
                    lowY = y
                }
                if (y > highY) {
                    highY = y
                }
            }
        }
    }


    return CGRect(x: lowX, y: lowY, width: highX-lowX, height: highY-lowY)
}
UIImage(cgImage: image.cgImage!.cropping(to: croppedRect)!)