IOS下实现高性能画板橡皮擦的办法

摘要

IOS下使用CAShapeLayer+UIBezierPath实现互动画板时橡皮擦的实现方式。

背景

要在IOS端做一个在线教育DEMO,集成音视频互动、PPT白板互动、聊天等功能。

画板实现

IOS画板有很多实现,主要有

  • DrawRect+UIBezierPath:实现比较简单,橡皮擦也好实现,但是CPU较高,内存消耗大。
  • CAShapeLayer+UIBezierPath:性能较好,使用GPU绘制,内存占用也小,但是橡皮擦比较难实现。
  • GLES:比较底层,开发要求较高。

综合以上各个方式的特点,产品中比较合适的方案是CAShapeLayer+UIBezierPath,绘制办法很简单:

  • 为了支持多方不同的线色、线宽,每一笔都创建一个新的CAShapeLayer,每一笔都是覆盖绘制;
  • 使用UIBezierPath描述路径,并将path传递给CAShapeLayer;
  • 调用UIView.layer的addSublayer,将CAShapeLayer绘制到当前View上;
  • 缓存CAShapeLayer,在需要撤销一笔的时候只需要调用CAShapeLayer的removeFromSuperlayer,在需要重画一笔的时候重新调用UIView.layer的addSublayer。

橡皮擦实现

橡皮擦本质上跟画线是一样的动作,只是线色是背景色,如果没有背景图片,只需要把线色设置成背景色就可以实现橡皮功能。但是在有背景图片的场景下会比较麻烦,单一背景色会覆盖背景图片。这个时候需要把背景色设置成背景图片,但是需要进行一定的变换,否则橡皮擦的背景图片会发生翻转,以下是核心代码:

                        //创建一个新的Context
                        UIGraphicsBeginImageContext(self.frame.size);
                        //获得当前Context
                        CGContextRef context = UIGraphicsGetCurrentContext();
                        //CTM变换,调整坐标系,*重要*,否则橡皮擦使用的背景图片会发生翻转。
                        CGContextScaleCTM(context, 1, -1);
                        CGContextTranslateCTM(context, 0, -self.bounds.size.height);
                        //图片适配到当前View的矩形区域,会有拉伸
                        [image drawInRect:self.bounds];
                        //获取拉伸并翻转后的图片
                        UIImage *stretchedImg = UIGraphicsGetImageFromCurrentImageContext();
                        //将变换后的图片设置为背景色
                        [self setBackgroundColor:[[UIColor alloc] initWithPatternImage:stretchedImg]];
                        //View的图层设置为原始图片,这里会自动翻转,经过这步后图层显示和橡皮背景都设置为正确的图片。
                        self.layer.contents = (_Nullable id)image.CGImage;
                        UIGraphicsEndImageContext();

代码和注释已经说明一切,CAShapeLayer+UIBezierPath的橡皮擦实现实际上也比较简单,只要知道原理。

另外有人的实现方式是把所有的CAShapeLayer图层合并成一张图片,然后在合并后的图片里使用UIBeizerPath的strokeWithBlendMode:kCGBlendModeClear进行混色,这也是一种办法,但是混色占用的CPU也会很高,相对来说,使用背景图片来当橡皮擦的画刷,性能是较好的。

你可能感兴趣的:(SDK,webrtc)