iOS-用户截屏、获取截屏图片

关于iOS用户截屏操作,此文以swift为例,库使用iOS8之后的Photos库
iOS7开始提供了UIApplicationUserDidTakeScreenshotNotification通知用来获取用户截屏的操作,一下介绍两种获取用户截屏图片的方式

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    NotificationCenter.default.addObserver(self, selector: #selector(getScreenshotOperation), name: Notification.Name.UIApplicationUserDidTakeScreenshot, object: nil)
}
//        收到用户截屏通知,获取图片,并对图片进行编辑
@objc func getScreenshotOperation(notification: Notification){
    AFPrint(message: "用户截屏了")
//        方式一:模拟用户截屏操作获取图片
    let takeScreenshotImage: UIImage = self.imageWithScreenshot()
    editImage(getCurrentImage: takeScreenshotImage)
//        方式二:从相册获取用户截屏图片(延迟的目的是确保截屏图片已存入到相册)
//      self.perform(#selector(AFHomeViewController.getLastPhoto), with: nil, afterDelay: 3)
}

方式一:根据模拟用户截屏操作来获取图片

// MARK: - 模拟用户截屏行为,获取图片
private func dataWithScreenshotInPNGFormat() -> Data{
    let imageSize: CGSize
    let orientation: UIInterfaceOrientation = UIApplication.shared.statusBarOrientation
    if UIInterfaceOrientationIsPortrait(orientation){
        imageSize = UIScreen.main.bounds.size
    }else{
        imageSize = CGSize(width: AFScreenWidth, height: AFScreenHeight)
    }
    UIGraphicsBeginImageContextWithOptions(imageSize, false, 0)
    let context: CGContext = UIGraphicsGetCurrentContext()!
    for window: UIWindow in UIApplication.shared.windows {
        context.saveGState()
        context.translateBy(x: window.center.x, y: window.center.y)
        context.concatenate(window.transform)
        context.translateBy(x: -window.bounds.size.width * window.layer.anchorPoint.x, y: -window.bounds.size.height * window.layer.anchorPoint.y)
        if orientation == .landscapeLeft{
            context.rotate(by: CGFloat(Double.pi / 2))
            context.translateBy(x: 0, y: -imageSize.width)
        }else if orientation == .landscapeRight{
            context.rotate(by: -CGFloat(Double.pi / 2))
            context.translateBy(x: -imageSize.height, y: 0)
        }else if orientation == .portraitUpsideDown{
            context.rotate(by: -CGFloat(Double.pi))
            context.translateBy(x: -imageSize.width, y: -imageSize.height)
        }
        
        if window.responds(to: #selector(UIView.drawHierarchy(in:afterScreenUpdates:))){
            window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
        }else{
            window.layer.render(in: context)
        }
        context.restoreGState()
    }
    
    let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    
    return UIImagePNGRepresentation(image)!
}
// MARK: - 获取用户截屏图片
private func imageWithScreenshot() -> UIImage{
    let imageData = self.dataWithScreenshotInPNGFormat()
    return UIImage(data: imageData)!
}

方法二:从相册中获取最新加入的图片

// MARK: - 获取相册中最后一张图片,即用户最新的截屏
@objc private func getLastPhoto(){
    let options: PHFetchOptions = PHFetchOptions()
    options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    let assetsFetchResults: PHFetchResult = PHAsset.fetchAssets(with: options)
    let phasset: PHAsset = assetsFetchResults.firstObject!
    let imageManager: PHCachingImageManager = PHCachingImageManager()
    imageManager.requestImage(for: phasset, targetSize: CGSize(width: AFScreenWidth, height: AFScreenHeight - AFTopHeight - AFTabbarHeight), contentMode: PHImageContentMode.aspectFit, options: nil) { (result, info) in
        self.editImage(getCurrentImage: result!)
//            删除原始图
        /*PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.deleteAssets([assetsFetchResults.firstObject, assetsFetchResults[1]] as NSFastEnumeration)
        }, completionHandler: { (success, error) in
            if success{
                AFPrint(message: "删除成功")
            }else{
                AFPrint(message: "删除失败")
            }
            
        })*/
    }
}

对获取到图片进行编辑

@objc private func editImage(getCurrentImage: UIImage){
    var takeScreenshotImage: UIImage = getCurrentImage
    //        显示图片
    let imageView: UIImageView = UIImageView(image: takeScreenshotImage)
    imageView.frame = CGRect(x: 0, y: AFTopHeight, width: AFScreenWidth, height: AFScreenHeight - AFTopHeight - AFTabbarHeight)
    self.view.addSubview(imageView)
    //        添加水印
    let point: CGPoint = CGPoint(x: 20, y: AFScreenHeight - AFTopHeight - AFTabbarHeight-30)
    let attributeString: NSDictionary = [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 14), NSAttributedStringKey.foregroundColor : UIColor.red, NSAttributedStringKey.backgroundColor : UIColor.yellow]
    takeScreenshotImage = self.addWaterTextWithImage(image: takeScreenshotImage, text: "版权归属xxx,违者必究", textPoint: point, attributeString: attributeString)
    imageView.image = takeScreenshotImage
    
    //            保存图片到相册
    PHPhotoLibrary.shared().performChanges({
        let req: PHAssetChangeRequest = PHAssetChangeRequest.creationRequestForAsset(from: takeScreenshotImage)
        AFPrint(message: req.creationDate)
    }, completionHandler: { (success, error) in
        
        AFPrint(message: "success " + "\(success)" + " error " + String(describing: error))
        
        if success{
            AFPrint(message: "保存成功")
        }else{
            AFPrint(message: "保存失败")
        }
        
    })
}
// MARK: - 图片添加文字水印
private func addWaterTextWithImage(image: UIImage, text: NSString, textPoint: CGPoint, attributeString: NSDictionary) -> UIImage{
//        开启上下文
    UIGraphicsBeginImageContextWithOptions(image.size, false, 0)
//        绘制图片
    image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
//        添加水印文字
    text.draw(at: textPoint, withAttributes: attributeString as? [NSAttributedStringKey : Any])
    let currentImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return currentImage
}

对于以上两种方式都存在一定的问题:
方式一:比如如果用户截屏上有类似toast提示,那么在用户截屏完成之后以及代码模仿用户截屏操作之前,有可能toast提示已经消失,那么就会造成用户的截屏以及代码模仿的用户截屏所获取的图片不同
方式二:获取相册最新添加的图片,有可能会存在最新的图片并不是用户截屏的图片

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,960评论 3 119
  • 她在酒馆多喝了几杯酒,摇摇晃晃的走出街区,独自一人坐上了出租,一边笑着一边流着眼泪。 司机师傅邹了邹眉头,本想拒载...
    林小淇阅读 355评论 0 0
  • 即使如此 我也要告诉你 在最最漆暗的夜空 藏着一首黎明的歌 歌中远岫的黄昏 都曾荒凉 都曾寂寞 在遇见你的季节里 ...
    蜗牛的猫阅读 200评论 0 3
  • 有些等待,是加重负担,是需要尽可能避免的。 我静静地站在1000米起点,与一排同班男生站在起点。既无平日的喧闹,...
    北固亭阅读 481评论 2 0
  • 我利用午休的时间,走出了办公室的门 。伸伸脖子,弯弯腰,使自己的身心放松了下来。 门前院子里的一棵棵荠菜,碧绿可爱...
    霞_9667阅读 798评论 35 53