吃晚饭的时候, 朋友发了一组图片过来, 让我抠个图; 对, 没听错, 知道我是程序猿, 所以让我抠个图;
抠图这个说法, UI 设计师们都接受不了; 身为程序猿当然要更高雅一些, 能敲代码的就绝不抠图;
好了, 进入正题; 其实分析一下, 需求也比较简单, 就是把图片中的白色或者接近白色的背景换为透明, 黑色签名露出来; 下面是 demo 效果图:
代码:
//将图片的背景置为透明
- (UIImage*)imageToTransparent:(UIImage*)image
{
//分配内存
const int imageWidth = image.size.width;
const int imageHeight = image.size.height;
size_t bytesPerRow = imageWidth * 4;
uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight);
//创建context
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
//遍历像素
int pixelNum = imageWidth * imageHeight;
uint32_t* pCurPtr = rgbImageBuf;
for (int i = 0; i < pixelNum; i++, pCurPtr++){
//接近白色
//将像素点转成子节数组来表示---ARGB
//ptr[0]:透明度,ptr[1]:R,ptr[2]:G,ptr[3]:B
//分别取出RGB值后。进行判断需不需要设成透明。
uint8_t* ptr = (uint8_t*)pCurPtr;
if (ptr[1] > 140 && ptr[2] > 140 && ptr[3] > 140) {
//当RGB值都大于140则比较接近白色的都将透明度设为0
//demo中的图片有点灰, 所以设置了140, 可以根据需要自行设置
ptr[0] = 0;
}
}
//将内存转成image
CGDataProviderRef dataProvider =CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, nil);
CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight,8, 32, bytesPerRow, colorSpace,kCGImageAlphaLast |kCGBitmapByteOrder32Little, dataProvider,NULL, true,kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
UIImage *resultUIImage = [UIImage imageWithCGImage:imageRef];
//释放
CGImageRelease(imageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return resultUIImage;
}
代码的逻辑比较清晰就不多说了, 最后附上 github 地址;
来源: https://juejin.im/post/5a329a42f265da430a509c4e