新浦京81707con > 注册购买 > iOS端如何实现对图片和视频的,CAShapeLayer和UIBe

原标题:iOS端如何实现对图片和视频的,CAShapeLayer和UIBe

浏览次数:125 时间:2020-04-20

图片 1彩票刮刮乐.png

注:看了别人写的东西,本人动手操作了三次,记录一下。前面写过贰遍近似二维码扫码分界面包车型客车效劳,跟这么些近乎。都以用同样的东西。
初藳链接:http://www.jianshu.com/p/a1e88a277975
一、近似qq谈天的图纸,图片有个角。
1.CALayer和UIView
自家的领会正是五个都是图层,功用成效相像,各自的秘籍也正如像,能够把layer通晓成view,layer是其余二个CA框架下的事物,view是UIKit框架下东西,看名字知道了。至于苹果为何不把四个二合一,看过一篇小说,说是为了选拔种种平台。有空再找找这一个小说,写的很滑稽。
2.貌似手提式有线话机分界面看见的都以view,view有个layer属性,能够操作layer。layer有个mask属性,乌Crane语意思就是面罩。所以大家见到的view其实是这么些面罩。
为了让图片体现个角,view没什么管理的,只可以动layer了。改进了面罩的样子,就高达了指标。
如图:

iOS端如何完毕对图片和摄像的 涂鸦,贴图,巴尔的摩克,高斯笔涂鸦等技术详明

库房地址,合意就star一下❤️

图片 2

一: 图片管理部分:

那是一个轻易却作用强盛的刮刮乐视图,几行代码就足以兑现刮刮乐效果,并且质量优质。上面有美丽的女生福利啊,相信小编,你会赏识的

QQ20170727-151909.png

1, 图片的涂鸦:

种类示范:

图片 3

image.png

图片 4

image.png

实现的要紧思路是运用贝塞尔绘制原理:
创制五个 IJSIPanDrawingView 全数的操作都将要此个UIView上面实现
创办model IJSIPath 用于绘制
先是在初阶化方法中创建二个手势: 在手势的点子中完毕下面包车型客车代码
大旨代码:
创造 IJSIPath 类 提供 属性和 增添初叶化 加多点的艺术 绘制方法等
开头化方法
先看 IJSI帕特h 这些类达成 首要的得以实现思路就是贝塞尔划线的思量

  (instancetype)pathToPoint:(CGPoint)beginPoint pathWidth:(CGFloat)pathWidth
{
    UIBezierPath *bezierPath = [UIBezierPath bezierPath]; // 线的路径
   // 设置相关的属性 并设置起始点
    [bezierPath moveToPoint:beginPoint];
    // 创建自己对象 将贝塞尔数据映射到  IJSIPath 这个类中
    IJSIPath *path = [[IJSIPath alloc] init];
    path.bezierPath = bezierPath;
    return path;
}

//曲线 这个方法主要是在移动的过程中将移动店和贝塞尔连接成线
- (void)pathLineToPoint:(CGPoint)movePoint;
{
    //判断绘图类型
    [self.bezierPath addLineToPoint:movePoint];
}

//  这个方法就是将上面的点连线并绘制成路径
- (void)drawPath
{
    [self.pathColor set];
    [self.bezierPath stroke]; // 根据坐标点连线
}

上面大家来看怎么在 IJSIPanDrawingView 这一个UIView中调用这几个点子, 首先制造二个手势 并在手势的艺术中贯彻;

 CGPoint currentDraggingPosition = [sender locationInView:self.drawingView]; //获取到的是手指点击屏幕实时的坐标点
    if (sender.state == UIGestureRecognizerStateBegan)                          //一个手势已经开始但尚未改变或者完成时
    {
        // 初始化一个UIBezierPath对象, 把起始点存储到UIBezierPath对象中, 用来存储所有的轨迹点
        IJSIPath *path = [IJSIPath pathToPoint:currentDraggingPosition pathWidth:self.panWidth != 0 ? self.panWidth : MAX(1, 4)];

        path.pathColor = self.panColor != nil ? self.panColor : [UIColor redColor];
        [self.allLineArr addObject:path];                      //添加路线
    }

    if (sender.state == UIGestureRecognizerStateChanged) //手势状态改变
    {
        // 获得数组中的最后一个UIBezierPath对象(因为我们每次都把UIBezierPath存入到数组最后一个,因此获取时也取最后一个)
        IJSIPath *path = [self.allLineArr lastObject];
        [path pathLineToPoint:currentDraggingPosition]; //添加点
        [self drawLine]; // 划线

    }

鉴于是在UIView中大家不接受 在 -(void卡塔尔国draw 方法中绘制 所以我们需求成立上下文,并将财富绘制作而成一张图纸再次来到给外部,具体的代码看上面包车型大巴兑现

- (void)drawLine
{
    CGSize size = self.drawingView.frame.size;
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); //创建一个基于位图的上下文/NO 设置透明
    CGContextRef context = UIGraphicsGetCurrentContext();  // 获取当前上下文
    CGContextSetAllowsAntialiasing(context, true);         //去掉锯齿
    CGContextSetShouldAntialias(context, true);
    for (IJSIPath *path in self.allLineArr)
    {
        [path drawPath];
    }
    self.drawingView.image = UIGraphicsGetImageFromCurrentImageContext(); //生成一个image对象,并将最终的结果反馈给外界
    UIGraphicsEndImageContext();
}

至今绘制的大招已经产生,假诺您想开接口给外部你能够直接绘制 self.drawingView.image 就可以如:

- (UIImage *)_buildImage
{   UIGraphicsBeginImageContextWithOptions(self.originalImageSize, NO, self.backImage.scale);
    [self.backImage drawAtPoint:CGPointZero];
    [self.drawingView.image drawInRect:CGRectMake(0, 0, self.originalImageSize.width, self.originalImageSize.height)];
    UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tmp;
}

言听计用我们都买过彩票刮刮乐,总是会抱着中山高校奖的景色去刮,希望团结是最幸运的那一个,刮中七百万,抱得女神归,今后走上人生顶峰。但实际往往是您囊中之中的几十块零钱,几分钟就被花费完结了许多应用软件也合併了这一作用,比方用支出宝线下开荒后就有刮刮乐。即便刮中的都以些没多大用的降价券,但延续会引发人去刮一刮,万一中了大奖呢

地方是原图,下边是改过后的,有了个角。

2, 特图和文字的实现

贴图和文字的贯彻原理其实是均等的,这里大家只讲怎么实现贴图:

图片 5

image.png

关键的光景思想便是两张图绘制到一道, 表情图片有众多的操作比如 画边框 移动 旋转 删除 掩盖划线框等等这样的 那几个不在此详细介绍,给位客观能够看SDK 的活龙活现落到实处
思路解析:
第一大家会把 贴图或许文字封装到 IJSIImputTextExportView(文字)IJSIMapViewExportView(贴图卡塔尔,其实这些能够知晓成就是多个UIView 不过那些UIView 里面有其余不相同的属性
因为大家的那些种类是直接对外展现,全部大家采用在controller 的view上操作, 大家再controller上创办四个 UIImageView 名字叫drawingView, 然后把地点的UIView 全部加上到那一个UIImageView上,上面就是基本的代码,那么些代码决定以此绘制的结果 代码如下:

- (void)_completeCallback:(void (^)(UIImage *image))completeCallback
{
     UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.backImageView.image.size.width, self.backImageView.image.size.height),
                                           NO,
                                           self.backImageView.image.scale);
    [self.backImageView.image drawAtPoint:CGPointZero];
    [_drawingView.image drawInRect:CGRectMake(0, -drawY, self.backImageView.image.size.width / WS, self.backImageView.image.size.height / HS)];
    for (UIView *subView in _drawingView.subviews)
    {
        UIView *exportView = subView;
        UIImage *textImg = [self.class _screenshot:exportView orientation:UIDeviceOrientationPortrait usePresentationLayer:YES];

        [textImg drawInRect:CGRectMake(exportView.js_left / selfRw, (exportView.js_top / selfRh) - drawY, sw, sh)];
    }

    UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    dispatch_async(dispatch_get_main_queue(), ^{
        UIImage *image = [UIImage imageWithCGImage:tmp.CGImage scale:self.backImageView.image.scale orientation:UIImageOrientationUp];
        if (completeCallback)
        {
            completeCallback(image);
        }
    });
}

主干的思路正是选拔用的 UI基特 提供的绘图方法,三个图层三个图层的去绘制

  [textImg drawInRect:CGRectMake( , , , )];

绘图部分基本形成,上边我们来讲讲 德雷斯顿格绘制和高斯模糊画笔设置

多说无益,先来探问达成的功用呢

    UIImageView *originalIMG = [[UIImageView alloc] initWithFrame:CGRectMake(20, 80, 60, 80)];
    originalIMG.image = [UIImage imageNamed:@"1111"];
    [self.view addSubview:originalIMG];

    UIImageView *IMG = [[UIImageView alloc] initWithFrame:CGRectMake(20, 200, 60, 80)];
    IMG.image = [UIImage imageNamed:@"1111"];
    [self.view addSubview:IMG];

    CGFloat imgWidth = IMG.frame.size.width;
    CGFloat imgHeight = IMG.frame.size.height;

    CGPoint point1 = CGPointMake(0, 0);
    CGPoint point2 = CGPointMake(imgWidth-20, 0);
    CGPoint point3 = CGPointMake(imgWidth-20, 30);
    CGPoint point4 = CGPointMake(imgWidth, 30);
    CGPoint point5 = CGPointMake(imgWidth-20, 50);
    CGPoint point6 = CGPointMake(imgWidth-20, imgHeight);
    CGPoint point7 = CGPointMake(0, imgHeight);

    UIBezierPath *path = [[UIBezierPath alloc] init];
    [path moveToPoint:point1];
    [path addLineToPoint:point2];
    [path addLineToPoint:point3];
    [path addLineToPoint:point4];
    [path addLineToPoint:point5];
    [path addLineToPoint:point6];
    [path addLineToPoint:point7];

    [path closePath];

    CAShapeLayer *myLayer = [[CAShapeLayer alloc] init];
    myLayer.path = path.CGPath;
    myLayer.fillColor = [UIColor redColor].CGColor;
    myLayer.lineWidth = 2;
    myLayer.strokeColor = [UIColor greenColor].CGColor;
    IMG.layer.mask = myLayer;
3, 埃德蒙顿克绘制

作者们先说说实现思路:
率先我们须求获得一张已经创设好的贝尔法斯特克图, 这里大家不研讨马普托克的算法,各位观者想钻探夏洛特克的算法 请看IJSExtension UIImage的归类
下边大家借使已经得到好了UIimage

第一看图层

图片 6

image.png

率先大家须要创建三个UIImage 展现完整的图片在,主固然在并未有展开埃德蒙顿克蒙版的是急需给顾客已经显得的错觉,
下边是内容的主导:
创办一个 IJSImageMosaicView 集成自UIView
咱俩安插他的UI
1, 首先要求创立一个 CALayer 这一层重大用于展示上边已经赢得好的埃德蒙顿克图
2, 大家再成立四个 CAShapeLayer 那个首假诺为着在拖动的时候绘制不法则的图样设置
3, 最入眼的少数正是 将 CAShapeLayer 对象设置给 CALayer 的mask 属性 CALayer 是贰个那一个屌爆了的习性本质如故一个 CALayer
因为mask是三个层,并且它最珍视的是它的概貌,所以mask若是是CALayer 时,日常设置它的contents属性来定义它的外观,要是mask是CAShapeLayer的时候时临时会设置它的path属性,让它和UIBezierPath来组合使用定义它的外观 我们那边的思绪正是依靠 CAShapeLayer 来贯彻这几个出来方案

现实代码如下:

- (void)_createdUI
{
    //添加layer(imageLayer)到self上
    self.imageLayer = [CALayer layer];
    self.imageLayer.frame = self.bounds;

    [self.layer addSublayer:self.imageLayer];

    self.shapeLayer = [CAShapeLayer layer];
    self.shapeLayer.strokeColor = [UIColor blueColor].CGColor; //不可设置clean, 主要是设置opacity和这个属性相关
    self.shapeLayer.fillColor = nil; // 此处必需置空,不能设置

    [self.layer addSublayer:self.shapeLayer];

    self.imageLayer.mask = self.shapeLayer; // 子视图完全遮盖马赛克视图
}

接下去便是 通过 CAShapeLayer 的path 属性进行不允许则额路线绘制等等
基本的代码独有一句话:

   CGMutablePathRef path = (__bridge CGMutablePathRef)([array objectAtIndex:i]);
   self.shapeLayer.path = path;

这中间会牵扯到 路线的贮存等等逻辑,进度不复杂这里不细致批注
上面大家来谈谈 CAShapeLayer 的path
咱俩领略 绘制图像相仿有上面二种进程

1,调用CGContextBeginPath
2,调用CGContextMoveToPoint来设置路线的起源
3,调用CGPathAddLineToPoint, CGPathAddArc, CGPathAddRect等函数增多路线
4,最终,大家需求调用fill或stroke来绘制出那么些路子或图片
当大家绘制路线时,Path的音讯就能够被Graphics context重新初始化。
只要大家想要保存path消息,并一再施用它,我们就能够用到CGPathCreatMutable申请路径,本文技巧为主就是这种方案
在开始touch的时候:

CGPathMoveToPoint(self.path, NULL, point.x, point.y);

在touch 过程中

CGPathAddLineToPoint(self.path, NULL, point.x, point.y);
然后
 CGMutablePathRef path = (__bridge CGMutablePathRef)([array objectAtIndex:i]);
self.shapeLayer.path = path;

到此整个纽伦堡克的逻辑已经管理实现

图片 7彩票刮刮乐.gif图片 8美眉刮刮乐.gif

率先新建贝塞尔曲线,依照测算好的次第点,增加直线,最终闭合曲线。如图(别人的图)

高斯画笔的兑现

上面大家再来说讲高斯画笔的达成
高斯画笔的得以实现和前边涂鸦的笔触基本相同都是接纳链接点的方式得以达成,笔者那边换了 更底层的方法来拍卖:
率先须求取得壹个高斯图,那个高斯的拿走格局这里不细心讲明
第一大家将点的成团放到三个数组,组成多个门路集结,我们再讲路线的集结放到三个数组中,指标是为着有撤废的操作等等

    // 创建上下文
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithPatternImage:self.gaussanViewGaussanImage].CGColor); // 设置高斯的颜色,就是从外界获取的颜色
   // 从对应的路径数组中取出对应的点 再取出对应的,

    CGContextMoveToPoint(context, p.x, p.y);
    CGContextAddLineToPoint(context, p.x, p.y);
    CGContextDrawPath(context, kCGPathStroke);

    // 将绘制的结果存储在内存中
    self.nowImage = UIGraphicsGetImageFromCurrentImageContext();

    // 结束绘制
    UIGraphicsEndImageContext();
    [self setNeedsDisplay];  // 将内容绘制到 self.view上

最后在

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    [self.nowImage drawInRect:rect];// 直接将图片绘制到当前的view上
}

到此图片管理部分骨干告竣
上边大家再来说讲 怎么管理录像

参照了一个称呼“撕掉她的行李装运”应用软件,效果特别sexy,有未有一种心跳加速,血脉膨胀的以为。(相信大家焦急想要体验一下了,点击

图片 9

摄像拍卖

这一部分我们先来讲说裁剪,这部分的从头到尾的经过封装到了 IJSEditSDK 那个sdk里面

图片 10

image.png

先是大家先看看摄像具体的操作

1 创造AVMutableComposition对象来加多摄像音频财富的

AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];

2 设置采撷区域

 NSRange videoRange = NSMakeRange(startTime, (endTime - startTime)); // 开始位置, 裁剪的长度
    CMTime startT = CMTimeMakeWithSeconds(videoRange.location, videoAsset.duration.timescale);
    CMTime videoDuration = CMTimeMakeWithSeconds(videoRange.length, videoAsset.duration.timescale); //截取长度videoDuration
    CMTimeRange timeRange = CMTimeRangeMake(startT, videoDuration);

3, 我们知晓摄像有 录制轨道和拍子轨道 下边包车型地铁操作便是将那连个轨道归拢

 // 3 - 视频通道  工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材
    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    /*TimeRange截取的范围长度   ofTrack来源  atTime插放在视频的时间位置*/
    [videoTrack insertTimeRange:timeRange
                        ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeVideo].count > 0) ? [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject : nil
                         atTime:kCMTimeZero
                          error:&error];

    //3.2 - 添加原有音频
    //视频声音采集(也可不执行这段代码不采集视频音轨,合并后的视频文件将没有视频原来的声音)
    AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [audioTrack insertTimeRange:timeRange
                        ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeAudio].count > 0) ? [videoAsset tracksWithMediaType:AVMediaTypeAudio].firstObject : nil
                         atTime:kCMTimeZero
                          error:&error];

平常性上面包车型地铁操作再次回到的录制,摄像的转会皆反常,所以都亟需做转账管理
转载的代码给位老铁去sdk里面看呢
谈到底一步,导出录像, 导出录制的靶子是 AVAssetExportSession
对那么些目的开展质量设置管理就足以了
到此录像裁剪就ok了,这几个管理的思路平日管理的是时间规定的,比方从第几秒裁剪到第几秒

在网络查找了一番,方案基本上正是这种:链接。宗旨代码:

QQ20170727-152029.png

录像的写道贴图和加水印

图片 11

image.png

那有个别操作大致的笔触是 将一张处理好的图纸等比例 增多到录制的
图表的拍卖和方面图片的拍卖同样的
主干代码

 videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

第贰个参数
注重的一步是 首先成立七个承载的视图层: CALayer *parentLayer
大家具有的操作举个例子加图Gavin字 加边框等等都以在这里个 calayer上做到,然后将大家的那几个parentLayer增加到 创制的 CALayer *videoLayer上

到此整片文书档案的本领大旨都早就深入分析达成,思路也已经营知道,各位大神能够看看SDK 打call一波了
https://github.com/wangjinshan/IJSPhotoSDK

-touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { // 触摸任意位置 UITouch *touch = touches.anyObject; // 触摸位置在图片上的坐标 CGPoint cententPoint = [touch locationInView:self.imageView]; // 设置清除点的大小 CGRect rect = CGRectMake(cententPoint.x, cententPoint.y, 20, 20); // 默认是去创建一个透明的视图 UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0); // 获取上下文 CGContextRef ref = UIGraphicsGetCurrentContext(); // 把imageView的layer映射到上下文中 [self.imageView.layer renderInContext:ref]; // 清除划过的区域 CGContextClearRect(ref, rect); // 获取图片 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 结束图片的画板, (意味着图片在上下文中消失) UIGraphicsEndImageContext(); self.imageView.image = image;}

接下来新建CAShapeLayer。把刚刚的曲线路径赋值给CAShapeLayer,最终改正view的layer的mask,面罩替换完了就突显出了想要的萧规曹随。
总计:CAShapeLayer是layer的子类,平常都以匹配贝塞尔曲线一同坐班。贝塞尔绘制路线,让后把门路给CAShapeLayer,CAShapeLayer就能够展现了。和view道理同样,二个view要想显示,必定攻克一定的尺寸frame,假诺尺寸是0就看不到它了。同理CAShapeLayer要想显示必得有尺寸,那些门路实际上正是它的尺码。

本文由新浦京81707con发布于注册购买,转载请注明出处:iOS端如何实现对图片和视频的,CAShapeLayer和UIBe

关键词: 新浦京81707con ios 视图 上瘾 可以发布的

上一篇:AVPlayer的那些坑,iOS学习45之多媒体操作

下一篇:没有了