1、Bitmap绘图简介:
✨重要
:因为图片的输出目标为Bitmap,而不是输出到UIView上;在控制器中并没有已经创建好的Bitmap图形上下文,所以,需要我们手动创建Bitmap图形上下文。注意:一定要区分自定义控件时是通过获取storyboard中关联的UIView的图形上下文,因为自定义控件是将图形上下文中的目标图形绘制到UIView上,所以,需要获取UIView的图形上下文;将绘制信息缓存至UIView的图形上下文中。而将图形绘制到Bitmap中,因为图片的输出目标为Bitmap不再是UIView,而程序中并没有已经存在的Bitmap图形上下文;所以,我们应该手动创建Bitmap图形上下文,将水印图片的绘制信息保存至Bitmap图形上下文中;将来Bitmap可以根据图形上下文绘制好图形,我们才能从Bitmap中获取绘制好的水印图片。
2、Bitmap基本绘图:
2-1、裁剪成圆形图片:
OC语言方式:
1./** 2. 裁剪成圆形图片 3. */ 4.- (void)clipImage{ 5. UIImage *image = [UIImage imageNamed:@"girl1"]; 6. 7. // 1. 开启位图图形上下文 8. UIGraphicsBeginImageContext(image.size); 9. // 2. 获取图形上下文, 可省略 10. // CGContextRef ctx = UIGraphicsGetCurrentContext(); 11. // 3. 设置裁剪范围, 注意: 此时是以位图图形上下文为参考坐标系 12. UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, image.size.height, image.size.height)]; 13. // 4. 裁剪 14. [path addClip]; 15. // 5. 绘制图片 16. [image drawAtPoint:CGPointZero]; 17. // 6. 获取裁剪后的图片 18. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 19. // 7. 更新imageView 20. self.imageView.image = newImage; 21. // 8. 关闭图形上下文 22. UIGraphicsEndImageContext(); 23.}
C语言方式:
1.- (void)drawRect:(CGRect)rect{ 2. // 1. 获取图形上下文 3. CGContextRef ctx = UIGraphicsGetCurrentContext(); 4. 5. // 2. 设置裁剪区域 6. CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 50, 50)); 7. 8. CGContextClip(ctx); // 裁剪view, 使view中只有裁剪区域能显示 9. 10. // 3. 显示图片 11. UIImage *image = [UIImage imageNamed:@"me"]; 12. [image drawAtPoint:CGPointMake(100, 100)]; 13. 14. // 4. 渲染其他图形(使用裁剪后的的图形上下文, 只能在指定区域显示图形) 15. CGContextAddRect(ctx, CGRectMake(0, 0, 100, 100)); 16. CGContextFillPath(ctx); // 渲染无效,图形上下文中已经设置裁剪区域只能在指定区域显示内容 17.}
2-2、裁剪带有圆环的图片:
OC语言方式:
1.- (void)viewDidLoad { 2. [super viewDidLoad]; 3. 4. UIImage *image = [UIImage imageNamed:@"girl1"]; 5. 6. // 1. 开启位图图形上下文 7. UIGraphicsBeginImageContext(CGSizeMake(imageWidth, imageWidth)); 8. // 2. 裁剪外环 9. UIBezierPath *path1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, imageWidth, imageWidth)]; 10. [path1 addClip]; 11. [[UIColor redColor] set]; 12. [path1 fill]; 13. 14. // 3. 设置裁剪范围, 注意: 此时是以位图图形上下文为参考坐标系 15. UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(imageWidth * 0.5, imageWidth * 0.5) radius:(imageWidth * 0.5) - 10 startAngle:0 endAngle:M_PI * 2 clockwise:YES]; 16. // 4. 裁剪 17. [path2 addClip]; 18. // 5. 绘制图片 19. [image drawAtPoint:CGPointMake(10, 10)]; 20. // 6. 获取裁剪后的图片 21. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 22. // 7. 更新imageView 23. self.imageView.image = newImage; 24. // 8. 关闭图形上下文 25. UIGraphicsEndImageContext(); 26.}
C语言方式:
1. UIImage *oldImage = [UIImage imageNamed:@"me"]; 2. 3. // MARK: - 绘制大圆 4. CGFloat borderW = 2; 5. CGFloat circleRaduis = oldImage.size.width * 0.5 + borderW; 6. CGFloat borderX = circleRaduis; 7. CGFloat borderY = borderX; 8. 9. // 1. 开启Bitmap图形上下文 10. CGFloat bitmapWidth = circleRaduis * 2; 11. CGSize bitmapSize = CGSizeMake(bitmapWidth, bitmapWidth); 12. UIGraphicsBeginImageContextWithOptions(bitmapSize, NO, 0.0); 13. 14. // 2. 获取图形上下文 15. CGContextRef ctx = UIGraphicsGetCurrentContext(); 16. 17. CGContextAddArc(ctx, borderX, borderY, circleRaduis, 0, M_PI * 2, 0); 18. [[UIColor whiteColor] setFill]; 19. // 1. 渲染 20. CGContextFillPath(ctx); 21. 22. // MARK: - 绘制小圆 23. CGFloat smallX = borderX; 24. CGFloat smallY = borderY; 25. CGFloat smallRaduis = circleRaduis - borderW; 26. 27. CGContextAddArc(ctx, smallX, smallY, smallRaduis, 0, M_PI * 2, 0); 28. 29. // 1. 裁剪 30. CGContextClip(ctx); 31. 32. // 2. 绘制 33. [oldImage drawAtPoint:CGPointMake(borderW, borderW)]; 34. 35. // 6. 获取图片 36. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 37. self.iconView.image = newImage; 38. 39. // 7. 关闭 40. UIGraphicsEndImageContext();
2-3、屏幕截图:
1. // MARK: - 屏幕截图 2. // 1. 开启图形上下文 3. UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0); 4. 5. // 2. 获取图形上下文 6. CGContextRef ctx = UIGraphicsGetCurrentContext(); 7. 8. // 3. 将view中的layer渲染到图形上下文中 9. [self.view.layer renderInContext:ctx]; 10. 11. // 4. 获取图片 12. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 13. 14. // 5. 压缩成PNG格式图片 15. NSData *data = UIImagePNGRepresentation(newImage); 16. 17. // 6. 写到桌面 18. [data writeToFile:@"/Users/hehuafeng/Desktop/abc.png" atomically:YES]; 19. 20. // 7. 关闭图形上下文 21. UIGraphicsEndImageContext();
1.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { 2. //[UIScreen mainScreen].scale 设备点与像素坐标的比例. 3. 4. //1.开启一个位图上下文 5. //UIGraphicsBeginImageContext(self.view.bounds.size); 6. 7. //opaque:不透明度 8. //缩放比例 9. //0 = [UIScreen mainScreen].scale 10. //scale:缩放比例. 11. //在C语言当中不会进行像素与点的转换. 12. UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0); 13. 14. //2.获取当前的上下文. 15. CGContextRef ctx = UIGraphicsGetCurrentContext(); 16. 17. //3.把View的内容绘制到上下文当中. 18. [self.view.layer renderInContext:ctx]; 19. 20. //4.从上下文当中生成一张图片 21. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 22. 23. //5.关闭上下文 24. UIGraphicsEndImageContext(); 25. 26. //把图片写入到电脑当中.(与电脑之间进行传输数据都是以二进制流形式传输) 27. //把图片转成二进制流 28. //NSData *data = UIImageJPEGRepresentation(newImage, 1); 29. NSData *data = UIImagePNGRepresentation(newImage); 30. [data writeToFile:@"/Users/xiaomage/Desktop/newImage.png" atomically:YES]; 31.}
2-4、制作水印图片:
1.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ 2. UIImage *backImage = [UIImage imageNamed:@"scene"]; 3. UIImage *logoImage = [UIImage imageNamed:@"logo"]; 4. 5. // 1. 创建Bitmap(位图)图形上下文(相当于创建UIImage对象, 开启位图图形上下文, 无需接收) 6. // CGSize size : 将来Bitmap(位图)的实际大小 7. // BOOL opaque : 不透明度 8. // CGFloat scale : 缩放比, 官方建议使用0.0 9. UIGraphicsBeginImageContextWithOptions(backImage.size, YES, 0.0); 10. 11. // 2. 绘制背景图片 12. CGFloat backImageX = 0; 13. CGFloat backImageY = 0; 14. CGFloat backImageW = backImage.size.width; 15. CGFloat backImageH = backImage.size.height; 16. 17. [backImage drawInRect:CGRectMake(backImageX, backImageY, backImageW, backImageH)]; 18. 19. // 3. 绘制水印图片 20. CGFloat margin = 8; 21. CGFloat scale = 0.1; 22. 23. CGFloat logoImageW = backImageW * scale; 24. CGFloat logoImageH = backImageH * scale; 25. CGFloat logoImageX = backImageW - logoImageW - margin; 26. CGFloat logoImageY = backImageH - logoImageH - margin; 27. 28. [logoImage drawInRect:CGRectMake(logoImageX, logoImageY, logoImageW, logoImageH)]; 29. 30. // 4. 从Bitmap中获取图片 31. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 32. self.imageView.image = newImage; 33. 34. // 5. 关闭图形上下文 35. UIGraphicsEndImageContext(); 36. 37. // 6. 将图片压缩成PNG格式 38. NSData *data = UIImagePNGRepresentation(newImage); 39. 40. NSString *path = @"/Users/hehuafeng/Desktop/water.png"; 41. [data writeToFile:path atomically:YES]; 42.}
2-5、保存至手机:
1./** 2. 将图片保存至相机 3. */ 4.- (void)saveToPhoto{ 5. // 1. 开启位图图形上下文 6. UIGraphicsBeginImageContext(self.view.bounds.size); 7. CGContextRef ctx = UIGraphicsGetCurrentContext(); 8. 9. // 2. 渲染 10. [self.imageView.layer renderInContext:ctx]; 11. 12. // 3. 获取图片 13. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 14. 15. // 3. 保存至手机 16. UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), @"哈哈"); 17. 18. // 4. 关闭位图图形上下文 19. UIGraphicsEndImageContext(); 20.} 21. 22./** 23. 将相片保存至手机必须实现的相应方法 24. */ 25.- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{ 26. NSLog(@"%@", contextInfo); 27.}
2-6、读取手机中的图片:
1.//照片 2.- (IBAction)photo:(id)sender { 3. //弹出系统的相册 4. UIImagePickerController *pickVC = [[UIImagePickerController alloc] init]; 5. 6. //设置照片的来源 7. pickVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; 8. 9. pickVC.delegate = self; 10. 11. [self presentViewController:pickVC animated:YES completion:nil]; 12. //[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:pickVC animated:YES completion:nil]; 13. //从中选择照片 14. //把照片绘制到画板当中. 15.} 16. 17.#pragma -mark UIImagePickerController代理方法 当选择照片完毕时调用. 18.- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { 19. 20. NSLog(@"%@",info); 21. UIImage *image = info[UIImagePickerControllerOriginalImage]; 22. 23. NSData *data = UIImageJPEGRepresentation(image, 0); 24. [data writeToFile:@"/Users/xiaomage/Desktop/image.jpg" atomically:YES]; 25. 26. //关闭照片选择器 27. [self dismissViewControllerAnimated:YES completion:nil]; 28.}
✨重要
:需要遵守这两个协议才能使用图片选择器的代理,UINavigationControllerDelegate,UIImagePickerControllerDelegate
。
2-7、擦除指定区域的图片:
1./** 2. 拖拽手势监听方法 3. */ 4.- (IBAction)pan:(UIPanGestureRecognizer *)pan { 5. // 1. 开启位图图形上下文 6. UIGraphicsBeginImageContext(self.view.bounds.size); 7. // 2. 获取位图图形上下文 8. CGContextRef ctx = UIGraphicsGetCurrentContext(); 9. 10. // MARK: - 绘制背景图片一定要在渲染之前, 否则无法达到叠加效果 11. UIImage *image = [UIImage imageNamed:@"girl3"]; 12. [image drawInRect:self.view.bounds]; 13. 14. // 3. 将imageView中的内容渲染到图形上下文中 15. [self.imageView.layer renderInContext:ctx]; 16. 17. // 4. 设置区域 18. CGPoint currentPoint = [pan locationInView:self.imageView]; 19. CGRect rect = CGRectMake(currentPoint.x - 15, currentPoint.y - 15, 30, 30); 20. // 5. 进行擦除 21. CGContextClearRect(ctx, rect); 22. 23. // 6. 获取新图片 24. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 25. 26. // 7. 设置到imageView 27. self.imageView.image = newImage; 28. 29. // 8. 关闭图形上下文 30. UIGraphicsEndPDFContext(); 31.}
2-8、截取指定区域的图片:
1.- (IBAction)pan:(UIPanGestureRecognizer *)pan { 2. // MARK: - 判断手势状态 3. if (pan.state == UIGestureRecognizerStateBegan) { 4. // MARK. 获取触摸点 5. CGPoint point = [pan locationInView:self.imageView]; 6. self.point = point; 7. 8. }else if(pan.state == UIGestureRecognizerStateChanged){ 9. // MARK. 获取当前点 10. CGPoint currentPoint = [pan locationInView:self.imageView]; 11. CGFloat width = currentPoint.x - self.point.x; 12. CGFloat height = currentPoint.y - self.point.y; 13. self.coverView.frame = CGRectMake(self.point.x, self.point.y, width, height); 14. 15. }else if (pan.state == UIGestureRecognizerStateEnded){ 16. // MARK - 确保imageView显示的图片与屏幕坐标一致 17. // 1. 开启位图图形上下文并获取 18. UIGraphicsBeginImageContext(self.view.bounds.size); 19. CGContextRef ctx = UIGraphicsGetCurrentContext(); 20. 21. // 2. 设置裁剪区域 22. UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.coverView.frame]; 23. [path addClip]; // 裁剪 24. 25. // 3. 截取屏幕 26. [self.imageView.layer renderInContext:ctx]; 27. UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 28. 29. // 4. 更新imageView显示的图片, 确保图片坐标与屏幕坐标一致 30. self.imageView.image = newImage; 31. // 5. 关闭位图图形上下文 32. UIGraphicsEndImageContext(); 33. 34. // 6. 移除 35. [self.coverView removeFromSuperview]; 36. } 37.}