幽灵图的实例注释
该方法:传入一个图片,返回一个添加了幽灵图片的新图。
- (UIImage )processUsingPixels:(UIImage)inputImage {
UInt32 * inputPixels; // 一个指针
/*
1、图片先转成位图,等待添加新图片
*/
CGImageRef inputCGImage = [inputImage CGImage];
NSUInteger inputWidth = CGImageGetWidth(inputCGImage);
NSUInteger inputHeight = CGImageGetHeight(inputCGImage);
// @1 颜色空间
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4;
NSUInteger bitsPerComponent = 8;
NSUInteger inputBytesPerRow = bytesPerPixel*inputWidth;
inputPixels = (UInt32 *)calloc(inputWidth * inputHeight, sizeof(UInt32));
// @2 位图内容
CGContextRef context = CGBitmapContextCreate(inputPixels, inputWidth, inputHeight,
bitsPerComponent, inputBytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(context, CGRectMake(0, 0, inputWidth, inputHeight), inputCGImage);
/*
2、将幽灵图,(提前计算好需要缩放成的大小)转换成位图
*/
UIImage * ghostImage = [UIImage imageNamed:@"ghost"];
CGImageRef ghostCGImage = [ghostImage CGImage];
CGFloat ghostImageAspectRatio = ghostImage.size.width / ghostImage.size.height;
NSInteger targetGhostWidth = inputWidth * 0.25;
CGSize ghostSize = CGSizeMake(targetGhostWidth, targetGhostWidth / ghostImageAspectRatio);
CGPoint ghostOrigin = CGPointMake(inputWidth * 0.5, inputHeight * 0.2);
NSUInteger ghostBytesPerRow = bytesPerPixel * ghostSize.width;
UInt32 * ghostPixels = (UInt32 *)calloc(ghostSize.width * ghostSize.height, sizeof(UInt32));
CGContextRef ghostContext = CGBitmapContextCreate(ghostPixels, ghostSize.width, ghostSize.height,
bitsPerComponent, ghostBytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(ghostContext, CGRectMake(0, 0, ghostSize.width, ghostSize.height),ghostCGImage);
/*
3、ghost图片在背景图上的起始点像素位置(依照背景图)
*/
NSUInteger offsetPixelCountForInput = ghostOrigin.y * inputWidth + ghostOrigin.x;
UInt32 count = 0;
NSLog(@"%f,%f",ghostSize.width,ghostSize.height);
/*
4、添加(重点!!!!!)
*/
// 循环遍历整个背景图
for (NSUInteger j = 0; j < ghostSize.height; j++) {
for (NSUInteger i = 0; i < ghostSize.width+1; i++) {
// // 新建指针,在ghostSize的位置上,指针指向相对于背景图的ghostSize的位置
UInt32 * inputPixel = inputPixels + j * inputWidth + i + offsetPixelCountForInput;
// 获取到背景图上该点的像素值
UInt32 inputColor = *inputPixel;
count++;
// NSLog(@"%d * %d + %d + %d -1 = %u",i,j,i,j,(unsigned int)count);
// 新建指针,获取到幽灵图上的对应位置,并指向!
UInt32 * ghostPixel = ghostPixels + j * (int)ghostSize.width + i;
// 获取到幽灵图上该点的像素值
UInt32 ghostColor = 0;
// NSLog(@"%x",*ghostPixel);
if (*ghostPixel > 0) {
ghostColor = *ghostPixel;
// NSLog(@"%x",(unsigned int)ghostColor);
}
// 两个像素值进行合并。
/*
每一个颜色都有一个透明通道来标识透明度。并且,你每创建一张图像,每一个像素都会有一个颜色值。
所以,如果遇到有透明度和半透明的颜色值该如何处理呢?
答案是,对透明度进行混合。在最顶层的颜色会使用一个公式与它后面的颜色进行混合。公式如下:
NewColor = TopColor * TopColor.Alpha + BottomColor * (1 - TopColor.Alpha)
当顶层透明度为1时,新的颜色值等于顶层颜色值。
当顶层透明度为0时,新的颜色值于底层颜色值。
最后,当顶层的透明度值是0到1之前的时候,新的颜色值会混合借于顶层和底层颜色值之间。
还可以用 premultiplied alpha的方法。
*/
// 将幽灵图像的每一个像素的透明通道都乘以了0.5,使它成为半透明状态。然后将它混合到图像中
CGFloat ghostAlpha = 0.5f * (A(ghostColor) / 255.0);
UInt32 newR = R(inputColor) * (1 - ghostAlpha) + R(ghostColor) * ghostAlpha;
UInt32 newG = G(inputColor) * (1 - ghostAlpha) + G(ghostColor) * ghostAlpha;
UInt32 newB = B(inputColor) * (1 - ghostAlpha) + B(ghostColor) * ghostAlpha;
// 将每个颜色的值范围进行限定到0到255之间,以防越界。
newR = MAX(0,MIN(255, newR));
newG = MAX(0,MIN(255, newG));
newB = MAX(0,MIN(255, newB));
// 像素拼接,设置ghostSize位置上的新像素
*inputPixel = RGBAMake(newR, newG, newB, A(inputColor));
// inputPixel = NULL;
// ghostPixel = NULL;
}
}
CGImageRef newCGImage = CGBitmapContextCreateImage(context);
UIImage * processedImage = [UIImage imageWithCGImage:newCGImage];
// 5. Cleanup!
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
CGContextRelease(ghostContext);
CGImageRelease(newCGImage);
free(inputPixels);
free(ghostPixels);
return processedImage;
}