1. 程式人生 > >iOS Quart2D繪圖之UIGraphicsBeginImageContextWithOptions基礎

iOS Quart2D繪圖之UIGraphicsBeginImageContextWithOptions基礎

主要是看看圖形上下文


如果你看到了這裡


內容不多,包括

  • 水印:給圖片新增水印(文字和圖片水印)
  • 裁剪:裁剪圓形圖片(帶邊框或者不帶)
  • 截圖:擷取當前螢幕
  • 擦除:這個不知道怎麼描述....

    不知怎麼描述擦除

.
.

OK,為了方便使用,我都寫在Image的分類中了,拿出來就可以使用!

.
.
.
.
.
.

1、圖形上下文:主要是對圖片進行處理,操作步驟基本如下,可在 2 之前或者之後對上下文進行處理

  • 1 開啟一個圖形上下文
  • 2 繪製圖片
  • 3 從當前上下文獲取新的圖片
  • 4 關閉上下文
+ (UIImage *)pq_drawImageWithImageNamed:(NSString
*)name{ //1.獲取圖片 UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:nil]]; //2.開啟圖形上下文 UIGraphicsBeginImageContext(image.size); //3.繪製到圖形上下文中 [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)]; //4.從上下文中獲取圖片 UIImage
* newImage = UIGraphicsGetImageFromCurrentImageContext(); //5.關閉圖形上下文 UIGraphicsEndImageContext(); //返回圖片 return newImage; }

3.png

.
.
.
.

2、給圖片新增文字水印:

  • 1 開啟一個圖形上下文
  • 2 繪製圖片
  • 3 把文字繪製到當前上下文
  • 4 從當前上下文獲取新的圖片
  • 5 關閉上下文
+ (UIImage *)pq_WaterImageWithImage:(UIImage *)image text:(NSString *)text textPoint:(CGPoint)point
attributedString:(NSDictionary * )attributed{ //1.開啟上下文 UIGraphicsBeginImageContextWithOptions(image.size, NO, 0); //2.繪製圖片 [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)]; //新增水印文字 [text drawAtPoint:point withAttributes:attributed]; //3.從上下文中獲取新圖片 UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext(); //4.關閉圖形上下文 UIGraphicsEndImageContext(); //返回圖片 return newImage; }

4.png

.
.
.
.

3、給圖片新增圖片水印:

  • 1 開啟一個圖形上下文
  • 2 繪製圖片
  • 3 把水印圖片繪製到當前上下文
  • 4 從當前上下文獲取新的圖片
  • 5 關閉上下文
+ (UIImage *)pq_WaterImageWithImage:(UIImage *)image waterImage:(UIImage *)waterImage waterImageRect:(CGRect)rect{

    //1.獲取圖片

    //2.開啟上下文
    UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
    //3.繪製背景圖片
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    //繪製水印圖片到當前上下文
    [waterImage drawInRect:rect];
    //4.從上下文中獲取新圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    //5.關閉圖形上下文
    UIGraphicsEndImageContext();
    //返回圖片
    return newImage;
}

5.png

.
.
.
.

4、裁剪圓形圖片:

  • 1 開啟一個圖形上下文
  • 2 設定裁剪區域
  • 3 把圖片繪製到當前上下文
  • 4 從當前上下文獲取新的圖片
  • 5 關閉上下文
+ (nullable UIImage *)pq_ClipCircleImageWithImage:(nullable UIImage *)image circleRect:(CGRect)rect{

    //1、開啟上下文
    UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);

    //2、設定裁剪區域
    UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:rect];
    [path addClip];

    //3、繪製圖片
    [image drawAtPoint:CGPointZero];

    //4、獲取新圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();

    //5、關閉上下文
    UIGraphicsEndImageContext();

    //6、返回新圖片
    return newImage;
}

6.png

.
.
.
.

5、裁剪帶邊框的圓形圖片:

  • 1 開啟一個圖形上下文
  • 2 設定邊框
  • 3 設定裁剪區域
  • 4 把圖片繪製到當前上下文
  • 5 從當前上下文獲取新的圖片
  • 6 關閉上下文
+ (nullable UIImage *)pq_ClipCircleImageWithImage:(nullable UIImage *)image circleRect:(CGRect)rect borderWidth:(CGFloat)borderW borderColor:(nullable UIColor *)borderColor{
    //1、開啟上下文
    UIGraphicsBeginImageContext(image.size);

    //2、設定邊框
    UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:rect];
    [borderColor setFill];
    [path fill];

    //3、設定裁剪區域
    UIBezierPath * clipPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(rect.origin.x + borderW , rect.origin.x + borderW , rect.size.width - borderW * 2, rect.size.height - borderW *2)];
    [clipPath addClip];

    //3、繪製圖片
    [image drawAtPoint:CGPointZero];

    //4、獲取新圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    //5、關閉上下文
    UIGraphicsEndImageContext();
    //6、返回新圖片
    return newImage;
}

7.png

.
.
.
.

6、截圖:

  • 1 開啟一個圖形上下文
  • 2 獲取當前上下文
  • 3 截圖,渲染到當前上下文中,這裡使用繪製無效,可自行測試
  • 4 從當前上下文獲取新的圖片
  • 5 把圖片轉化成為NSData型別
  • 6 關閉上下文
  • 7 把新的圖片和NSData型別直接放回,便於顯示和儲存截圖
+ (void)pq_cutScreenWithView:(nullable UIView *)view successBlock:(nullable void(^)(UIImage * _Nullable image,NSData * _Nullable imagedata))block{
    //1、開啟上下文
    UIGraphicsBeginImageContext(view.bounds.size);

    //2.獲取當前上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //3.截圖
    [view.layer renderInContext:ctx];

    //4、獲取新圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();

    //5.轉化成為Data
    //compressionQuality:表示壓縮比 0 - 1的取值範圍
    NSData * data = UIImageJPEGRepresentation(newImage, 1);
    //6、關閉上下文
    UIGraphicsEndImageContext();

    //7.回撥
    block(newImage,data);
}

8.png
9.png

.
.
.
.

7、擦除:


10.png
  • 1 計算當前擦除區域的大小位置:


    11.png
  • 2 開啟上下文

  • 3 獲取當前上下文

  • 4 把圖片繪製到當前上下文

  • 5 裁剪出透明區域

  • 6 得到當前上下文的圖片

  • 7 關閉上下文

  • 8 把圖片設定給前景ImageView

- (void)wipePanGestureEvent:(UIPanGestureRecognizer * )pan{
    //計算位置
    CGPoint nowPoint = [pan locationInView:self.wipeImageV];
    CGFloat offsetX = nowPoint.x - 10;
    CGFloat offsetY = nowPoint.y - 10;
    CGRect clipRect = CGRectMake(offsetX, offsetY, 20, 20);

    //開啟上下文
    UIGraphicsBeginImageContextWithOptions(self.wipeImageV.bounds.size, NO, 1);
    //獲取當前的上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //把圖片繪製上去
    [self.wipeImageV.layer renderInContext:ctx];

    //把這一塊設定為透明
    CGContextClearRect(ctx, clipRect);

    //獲取新的圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();

    //關閉上下文
    UIGraphicsEndImageContext();

    //重新賦值圖片
    self.wipeImageV.image = newImage;

}

為了程式碼能複用,作者再次把這個程式碼封裝到了Image類別中:

- (nullable UIImage *)pq_wipeImageWithView:(nullable UIView *)view currentPoint:(CGPoint)nowPoint size:(CGSize)size{
    //計算位置
    CGFloat offsetX = nowPoint.x - size.width * 0.5;
    CGFloat offsetY = nowPoint.y - size.height * 0.5;
    CGRect clipRect = CGRectMake(offsetX, offsetY, size.width, size.height);

    //開啟上下文
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 1);
    //獲取當前的上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //把圖片繪製上去
    [view.layer renderInContext:ctx];

    //把這一塊設定為透明
    CGContextClearRect(ctx, clipRect);

    //獲取新的圖片
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();

    //關閉上下文
    UIGraphicsEndImageContext();

    //重新賦值圖片
    return newImage;
}

外面直接呼叫

//封裝後如下
    self.wipeImageV.image = [self.wipeImageV.image pq_wipeImageWithView:self.wipeImageV currentPoint:[pan locationInView:self.wipeImageV] size:CGSizeMake(20, 20)];

效果圖如下:
沒擦除之前:


擦除之前

擦除之後:


擦除之後
效果圖

.
.
.
.

8、圖片裁剪:

之前都是固定區域、固定形狀的裁剪,現在我們做一個自己選擇大小,範圍的裁剪。
  • 走一遍思想(個人想法,如果你有更好的,歡迎指正):

思路

然後因為這個區域是自己控制大小的!
所以要建立一個View

移動:思路就是獲取當前的點加上偏移量


圖片


實現方法有兩種,一種是新增Pan事件,一種直接重寫touches系列方法
我採用後者。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch * touch = [touches anyObject];
    //得到按下去的點
    _startP = [touch locationInView:self];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch * touch = [touches anyObject];

    CGPoint curP = [touch locationInView:self];


//計算偏移量
    CGFloat x = curP.x - _startP.x;
    CGFloat y = curP.y - _startP.y;

    //限制範圍 不允許超出螢幕

    self.x += x;
    if (self.x <=0) {
        self.x = 0;
    }
    self.y += y;
    if (self.y <= 0) {
        self.y = 0;
    }
    //範圍判斷
    [self ifOut];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

}

大小變換:


大小
- (IBAction)sizePan:(UIPanGestureRecognizer *)sender {

    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
            _sizeStartP = [sender locationInView:self];
            oldSize = self.size;
            break;

    case UIGestureRecognizerStateChanged:
        {
            CGPoint curP = [sender locationInView:self ];

            CGFloat w = curP.x  - _sizeStartP.x;
            CGFloat h = curP.y  - _sizeStartP.y;

            self.width = oldSize.width + w;
            self.height = oldSize.height + h;

            [self ifOut];
        }
            break;

        default:
            break;
    }
}

剪下過程:


裁剪過程
+ (void)pq_cutScreenWithView:(nullable UIView *)view cutFrame:(CGRect)frame successBlock:(nullable void(^)(UIImage * _Nullable image,NSData * _Nullable imagedata))block{

    //先把裁剪區域上面顯示的層隱藏掉
    for (PQWipeView * wipe in view.subviews) {
        [wipe setHidden:YES];
    }


    // ************************   進行第一次裁剪 ********************

    //1.開啟上下文
    UIGraphicsBeginImageContext(view.frame.size);
    //2、獲取當前的上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //3、新增裁剪區域
    UIBezierPath * path = [UIBezierPath bezierPathWithRect:frame];
    [path addClip];
    //4、渲染
    [view.layer renderInContext:ctx];
    //5、從上下文中獲取
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    //7、關閉上下文
    UIGraphicsEndImageContext();

    //8、進行完第一次裁剪之後,我們就已經拿到了沒有半透明層的圖片,這個時候可以恢復顯示
    for (PQWipeView * wipe in view.subviews) {
        [wipe setHidden:NO];
    }

    // ************************   進行第二次裁剪 ********************
    //9、開啟上下文,這個時候的大小就是我們最終要顯示圖片的大小
    UIGraphicsBeginImageContextWithOptions(frame.size, NO, 0);

    //10、這裡把x y 座標向左、上移動
    [newImage drawAtPoint:CGPointMake(- frame.origin.x, - frame.origin.y)];

    //11、得到要顯示區域的圖片
    UIImage * fImage = UIGraphicsGetImageFromCurrentImageContext();
    //12、得到data型別 便於儲存
    NSData * data2 = UIImageJPEGRepresentation(fImage, 1);
    //13、關閉上下文
    UIGraphicsEndImageContext();
    //14、回撥
    block(fImage,data2);
}

這裡在說說二次裁剪吧:


二次裁剪

效果圖:
原始大小:


18.png

改變之後


19.png

點選裁剪:


20.png

裁減之後:


效果圖

沙河路徑:


終於寫完啦!!!!