美文网首页iOS开发(OC)iOS学习专题iOS开发经验集
iOS APP界面黑白化处理(灰度处理)(为悼念日准备)

iOS APP界面黑白化处理(灰度处理)(为悼念日准备)

作者: suoluomen | 来源:发表于2020-05-15 15:02 被阅读0次
  • 2020年初,新冠病毒悄然来袭,上万的民众深受其害,不幸者丧失生命达三千余人,还好政府及时组织医疗团队、制定防护相关措施于四月初得以控制,并在2020年4月4日举国哀悼,哀悼逝去英雄!互联网各大网站、app界面全部变成黑白色以示哀悼。
    网页端、安卓端的同学很快完成相关实现,只剩下iOS端干瞪眼,拜读了鸿洋大神的博客,了解安卓和网页的实现过程。尝试在iOS端尝试却未能成功。但是iPhone手机-->设置-->辅助功能-->显示与文字大小--> 色彩滤镜--> 灰度功能打开,整个手机都黑化了,但这总不能告诉用户打开吧,尴尬。

*最后绞尽脑汁,经高人指点:既然无法像安卓、网页大神那样“一行代码实现黑白化”,那就分步实施吧。于是我们分了三步走:

  1. 图片二值化处理
  2. color
  3. H5页面

*知识点:

  1. 颜色空间,苹果默认使用RGB
  2. RGB灰度处理算法
1. 图片的二值化处理

*图片的二值化处理,百度一下很多,这里我们使用的是bitmap,将每一个色值取出根据灰度算法计算后改变原来的色值。优点是生成的图片不会出现锯齿,模糊现象。核心代码:

- (UIImage *)grayImage {
    const int RED =1;
    const int GREEN =2;
    const int BLUE =3;
    
    // Create image rectangle with current image width/height
    CGRect imageRect = CGRectMake(0,0, self.size.width* self.scale, self.size.height* self.scale);
    
    int width = imageRect.size.width;
    int height = imageRect.size.height;
    
    // the pixels will be painted to this array
    uint32_t *pixels = (uint32_t*) malloc(width * height *sizeof(uint32_t));
    
    // clear the pixels so any transparency is preserved
    memset(pixels,0, width * height *sizeof(uint32_t));
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // create a context with RGBA pixels
    CGContextRef context = CGBitmapContextCreate(pixels, width, height,8, width *sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    
    // paint the bitmap to our context which will fill in the pixels array
    CGContextDrawImage(context,CGRectMake(0,0, width, height), [self CGImage]);
    
    for(int y = 0; y < height; y++) {
        for(int x = 0; x < width; x++) {
            uint8_t *rgbaPixel = (uint8_t*) &pixels[y * width + x];
            
            // convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
            uint32_t gray = 0.3 * rgbaPixel[RED] +0.59 * rgbaPixel[GREEN] +0.11 * rgbaPixel[BLUE];
            
            // set the pixels to gray
            rgbaPixel[RED] = gray;
            rgbaPixel[GREEN] = gray;
            rgbaPixel[BLUE] = gray;
        }
    }
    
    // create a new CGImageRef from our context with the modified pixels
    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    
    // we're done with the context, color space, and pixels
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(pixels);
    
    // make a new UIImage to return
    UIImage *resultUIImage = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:UIImageOrientationUp];
    
    // we're done with image now too
    CGImageRelease(imageRef);
    
    return resultUIImage;
}
2. 颜色color
  • 我们想所有的控件不管是背景色、边框颜色、文字颜色等,最终都会调用UIColor中的一个API:
+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

*因此我们只需运用runtime进行方法交换,之后在交换的方法中将RGB进行灰度算法处理,alpha跟随设置不做处理。得到的color也就变成了对应的灰度,将color赋值后确实有很大惊喜,全量设置颜色的控件都实现了灰度化。核心代码如下:

+ (UIColor *)changeGrayWithColor:(UIColor *)color Red:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a {
    CGFloat gray = r * 0.299 +g * 0.587 + b * 0.114;
    UIColor *grayColor = [UIColor colorWithWhite:gray alpha:a];
    return  grayColor;
}
3. H5页面

*H5页面相对比较简单,至少从前端同事得到帮助。帮助书写了js代码,验证有效后,便是iOS端寻找注入时机。由于项目中WK和UIWeb并存,所有都要做处理。首先是UIWebView的注入,我们尝试在delegate的didFinishNavigation方法中注入,测试发现为时晚矣,界面加载出来后,显示的是正常颜色,然后再变成灰色,显然这是注入晚了。于是查看UIwebview的所有API,寻找注入时机。最后我们发现:

-(void)webView:(id)arg1 resource:(id)arg2 didFinishLoadingFromDataSource:(id)arg3 ;
  • 因此又一次使用了runtime方法交换,拦截到上面API时,在其中注入js代码,完美的解决了闪一下变灰的问题,具体代码如下:
-(void)swizzled_webView:(id)arg1 resource:(id)arg2 didFinishLoadingFromDataSource:(id)arg3 {
    [self grayWebaction:arg1];
    [self swizzled_webView:arg1 resource:arg2 didFinishLoadingFromDataSource:arg3];
}

-(void)grayWebaction:(UIWebView *)web {
    NSString *params = @"var filter = '-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%); -ms-filter:grayscale(100%); -o-filter:grayscale(100%) filter:grayscale(100%);';document.getElementsByTagName('html')[0].style.filter = 'grayscale(100%)';";
    [web stringByEvaluatingJavaScriptFromString:params];
}

*至于WKWebview,不同于UIWebview,可以在初始化时直接注入js代码,便能实现其效果,当然也是通过方法交换,趁此档口注入js,具体代码如下:

- (instancetype)lg_initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration {
    // js脚本
    NSString *jScript = @"var filter = '-webkit-filter:grayscale(100%);-moz-filter:grayscale(100%); -ms-filter:grayscale(100%); -o-filter:grayscale(100%) filter:grayscale(100%);';document.getElementsByTagName('html')[0].style.filter = 'grayscale(100%)';";
    // 注入
    WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
                 
    WKUserContentController *wkUController = [[WKUserContentController alloc] init];
       [wkUController addUserScript:wkUScript];
    // 配置对象
    WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
    wkWebConfig.userContentController = wkUController;
    configuration = wkWebConfig;
    WKWebView *webView = [self lg_initWithFrame:frame configuration:configuration];
    return webView;
}
以上便是三步走的过程,也是摸着石头过河,不知道有没有更好地方法,万望大神指教。上面代码文件下载位置,提取码: 7nhg,代码中只是做了灰度效果实现,至于添加标志位判断是否要灰度处理,自己添加。

相关文章

网友评论

    本文标题:iOS APP界面黑白化处理(灰度处理)(为悼念日准备)

    本文链接:https://www.haomeiwen.com/subject/nrqcohtx.html