尝试动态为透明 UIImage 着色,但结果始终模糊。我做错了什么?

发布于 2024-10-01 10:05:14 字数 2127 浏览 2 评论 0原文

我的 iPhone 应用程序具有自定义 UITableViewCell,每个都有一个图标。在正常的单元格状态下,这些图标是黑色的,背景透明。我不想将第二组反转图标与应用程序捆绑在一起以实现突出显示状态(透明背景上的白色),而是希望在用户触摸相应的表格单元格时使用 Core Graphics 即时反转这些图标。

我找到了一些与用颜色覆盖 UIImage 或重新着色 UIImage 相关的其他答案,但所有这些技术都会为我产生模糊的结果(请参阅以下)。我尝试过各种 CGBlendMode ,以及手动计算更准确的蒙版(也许我做得不正确),但图标边缘周围的半透明像素似乎是它们的不透明度被破坏或基本上被丢弃 - 呈现出不稳定/模糊的外观。我对自己做错的事情感到不知所措。

它也不是真正改变我的所有图标的选项,使它们只是纯黑/白,没有透明度 - 我需要图标位于透明背景上,以便它们也可以覆盖在其他 UI 元素之上。

我用来反转图标的代码(由 Chadwick Wood 提供)(我在每个原始图标上调用此方法并传入 [UIColor WhiteColor] 作为第二个参数)和示例输出(在装有 iOS 4.1 的 iPhone 4 上)如下(忽略突出显示图像上的蓝色背景 - 它是所选表格单元格的突出显示背景)。

非常感谢任何帮助。

示例输入&输出:

程序化重新着色之前和之后的图标。

@implementation UIImage(FFExtensions)

+ (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color {

 // load the image
 UIImage *img = [UIImage imageNamed:name];

 // begin a new image context, to draw our colored image onto
 UIGraphicsBeginImageContext(img.size);

 // get a reference to that context we created
 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

 // set the fill color
 [color setFill];

 // translate/flip the graphics context (for transforming from CG* coords to UI* coords
 CGContextTranslateCTM(context, 0, img.size.height);
 CGContextScaleCTM(context, 1.0, -1.0);

 // set the blend mode to color burn, and the original image
 CGContextSetBlendMode(context, kCGBlendModeMultiply);
 CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
 //CGContextDrawImage(context, rect, img.CGImage);

 // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
 CGContextClipToMask(context, rect, img.CGImage);
 CGContextAddRect(context, rect);
 CGContextDrawPath(context,kCGPathFill);


 // generate a new UIImage from the graphics context we drew onto
 UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();

 //return the color-burned image
 return coloredImg;
}

@end

My iPhone app features custom UITableViewCells that each feature an icon. In the normal cell state, these icons are black with a transparent background. Instead of bundling a second set of inverted icons with the app for a highlighted state (white on a transparent background) I'd like to invert these icons on-the-fly using Core Graphics whenever the user touches the corresponding table cell.

I've found some other answers related to overlaying a UIImage with a color, or re-coloring UIImages, but all of these techniques produce a blurry result for me (see below). I've tried all kinds of CGBlendModes, as well as manually computing a more accurate mask (perhaps I did it incorrectly), but it seems that the semi-transparent pixels around the edges of my icons are getting their opacity borked or are basically being dropped - giving a choppy/blurred appearance. I'm at a loss for what I'm doing wrong.

It's also not really an option to change all my icons so that are just pure black/white with no transparency - I need the icons to sit on a transparent background so that they can be overlaid on top of other UI elements as well.

The code (courtesy of Chadwick Wood) that I'm using to invert the icon (I'm calling this method on each of my original icons and passing in [UIColor whiteColor] as the second argument) and example output (on an iPhone 4 with iOS 4.1) is below (ignore the blue background on the highlighted image - it is the highlighted background of a selected table cell).

Any help is greatly appreciated.

Example input & output:

Icon before & after programmatic recoloring.

@implementation UIImage(FFExtensions)

+ (UIImage *)imageNamed:(NSString *)name withColor:(UIColor *)color {

 // load the image
 UIImage *img = [UIImage imageNamed:name];

 // begin a new image context, to draw our colored image onto
 UIGraphicsBeginImageContext(img.size);

 // get a reference to that context we created
 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

 // set the fill color
 [color setFill];

 // translate/flip the graphics context (for transforming from CG* coords to UI* coords
 CGContextTranslateCTM(context, 0, img.size.height);
 CGContextScaleCTM(context, 1.0, -1.0);

 // set the blend mode to color burn, and the original image
 CGContextSetBlendMode(context, kCGBlendModeMultiply);
 CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
 //CGContextDrawImage(context, rect, img.CGImage);

 // set a mask that matches the shape of the image, then draw (color burn) a colored rectangle
 CGContextClipToMask(context, rect, img.CGImage);
 CGContextAddRect(context, rect);
 CGContextDrawPath(context,kCGPathFill);


 // generate a new UIImage from the graphics context we drew onto
 UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();

 //return the color-burned image
 return coloredImg;
}

@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

じ违心 2024-10-08 10:05:14

感谢彼得和史蒂文观察到输出图像的分辨率似乎低于输入图像,我意识到在创建图像上下文时我没有考虑屏幕的比例因子。

更改线路:

UIGraphicsBeginImageContext(img.size);

解决

UIGraphicsBeginImageContextWithOptions(img.size, NO, [UIScreen mainScreen].scale);

问题。

Thanks to Peter & Steven's observation that the resolution of the output image seemed to be lower than the input, I realized that I was not accounting for the scale factor of the screen when creating my image context.

Changing the line:

UIGraphicsBeginImageContext(img.size);

to

UIGraphicsBeginImageContextWithOptions(img.size, NO, [UIScreen mainScreen].scale);

fixes the problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文