1.flutter-截屏组件
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class RepaintBoundaryPage extends StatefulWidget {
@override
_RepaintBoundaryPageState createState() => _RepaintBoundaryPageState();
}
class _RepaintBoundaryPageState extends State<RepaintBoundaryPage> {
//全局key
GlobalKey _rootWidgetKey = GlobalKey();
//图片数组
List<Uint8List> _images = List();
///截图
Future<Uint8List> _capturePng(
GlobalKey globalKey, {
double pixelRatio = 1.0, //截屏的图片与原图的比例
}) async {
try {
RenderRepaintBoundary boundary =
globalKey.currentContext.findRenderObject();
var image = await boundary.toImage(pixelRatio: pixelRatio);
ByteData byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
return pngBytes;
} catch (e) {
print(e);
}
return null;
}
///build
@override
Widget build(BuildContext context) {
//RepaintBoundary 截屏组件
return RepaintBoundary(
key: _rootWidgetKey,
child: Scaffold(
appBar: AppBar(
title: Text("flutter组件截图"),
),
body: Column(
children: <Widget>[
FlatButton(
onPressed: () {
//获取截屏图像
Future<Uint8List> pngBytes = _capturePng(_rootWidgetKey);
//添加到图片数组中
pngBytes.then((Uint8List value) {
_images.add(value);
});
setState(() {});
},
child: Text("全屏截图"),
),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return Image.memory(
_images[index],
fit: BoxFit.cover,
);
},
itemCount: _images.length,
scrollDirection: Axis.horizontal,
),
)
],
),
),
);
}
}
2.flutter-截屏插件
screenshot: ^0.2.0
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:screenshot/screenshot.dart';
class FlutterScreenshotsPage extends StatefulWidget {
@override
_FlutterScreenshotsPageState createState() => _FlutterScreenshotsPageState();
}
class _FlutterScreenshotsPageState extends State<FlutterScreenshotsPage> {
//截屏图片路径
File _imageFile;
//截屏控制器
ScreenshotController screenshotController = ScreenshotController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("flutter插件截屏"),
),
body: Container(
child: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//截屏组件
Screenshot(
controller: screenshotController,
child: Column(
children: <Widget>[
Text('截屏的位置'),
FlutterLogo(),
],
),
),
_imageFile != null ? Image.file(_imageFile) : Container(),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_imageFile = null;
screenshotController
.capture(delay: Duration(milliseconds: 10))
.then((File image) async {
setState(() {
_imageFile = image;
});
print("File Saved to Gallery");
}).catchError((onError) {
print(onError);
});
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
3.flutter-iOS原生截屏
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class IosScreenshotsPage extends StatefulWidget {
@override
_IosScreenshotsPageState createState() => _IosScreenshotsPageState();
}
class _IosScreenshotsPageState extends State<IosScreenshotsPage> {
//平台信道
MethodChannel _channel = MethodChannel("Screenshots");
bool _image = false;
Uint8List _image8List;
//图片
///initState
@override
void initState() {
//监听原生
_channel.setMethodCallHandler((call) {
//接收截屏后的图片
if (call.method == "endScreenshots") {
Map map = call.arguments;
_image8List = map["image"];
_image = true;
print("接收原生的图片数据: $_image8List");
setState(() {});
}
return null;
});
super.initState();
}
///build
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("iOS原生截屏"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
OutlineButton(
onPressed: () {
//发送开始截屏到原生
_channel.invokeMethod("startScreenshots");
},
child: Text("发起截屏"),
),
Expanded(
child: _image
? Image.memory(
_image8List,
fit: BoxFit.cover,
)
: Container(),
),
],
),
),
);
}
}
iOS代码
//
// ScreenshotsManager.h
// Runner
//
// Created by macmini on 2020/9/15.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 协议
@protocol ScreenshotsManagerDelegate <NSObject>
/// 图片保存结果
- (void)isSaveImage:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
@end
/// 截屏类
@interface ScreenshotsManager : NSObject
/// 代理
@property(nonatomic,assign)id<ScreenshotsManagerDelegate>delegate;
/// 初始化
+ (instancetype)shareInstance;
/// 返回系统级截屏PNG数据
- (NSData *)screenshotsDataFromUIImagePNGRepresentation;
/// 返回系统级截屏JPG数据
- (NSData *)screenshotsDataFromUIImageJPEGRepresentation;
/// 返回系统级截屏图片
- (UIImage *)imageFromScreenshots;
/// 保存图片到本地
/// @param savedImage 需保存的图片
- (void)saveImageToPhotos:(UIImage*)savedImage;
@end
NS_ASSUME_NONNULL_END
//
// ScreenshotsManager.m
// Runner
//
// Created by macmini on 2020/9/15.
//
#import "ScreenshotsManager.h"
@implementation ScreenshotsManager
///强指针,应用结束才会死
static id _instance;
///外调单例方法
+ (instancetype)shareInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
///根本上只建立一个对象,只开辟一个内存
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
///防止copy时,新建立一个对象,保证只开辟一个内存
- (id)copyWithZone:(nullable NSZone *)zone
{
return _instance;
}
/************************************以上为单例****************************************/
#pragma mark - 系统级截屏
/// 返回系统级截屏PNG数据
- (NSData *)screenshotsDataFromUIImagePNGRepresentation
{
UIImage *image = [self imageFromScreenshots];
return UIImagePNGRepresentation(image);
}
/// 返回系统级截屏JPG数据
- (NSData *)screenshotsDataFromUIImageJPEGRepresentation
{
UIImage *image = [self imageFromScreenshots];
return UIImageJPEGRepresentation(image, 1.0f);
}
/// 返回系统级截屏图片
- (UIImage *)imageFromScreenshots
{
CGSize imageSize = CGSizeZero;
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsPortrait(orientation))
{
imageSize = [UIScreen mainScreen].bounds.size;
}
else {
imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
}
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
CGContextSaveGState(context);
CGContextTranslateCTM(context, window.center.x, window.center.y);
CGContextConcatCTM(context, window.transform);
CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
if (orientation == UIInterfaceOrientationLandscapeLeft)
{
CGContextRotateCTM(context, M_PI_2);
CGContextTranslateCTM(context, 0, -imageSize.width);
}
else if (orientation == UIInterfaceOrientationLandscapeRight)
{
CGContextRotateCTM(context, -M_PI_2);
CGContextTranslateCTM(context, -imageSize.height, 0);
}
else if (orientation == UIInterfaceOrientationPortraitUpsideDown)
{
CGContextRotateCTM(context, M_PI);
CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
}
if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
[window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
}
else {
[window.layer renderInContext:context];
}
CGContextRestoreGState(context);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark - 将图片保存到相册
//保存图片到本地
- (void)saveImageToPhotos:(UIImage*)savedImage
{
UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
// 指定回调方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
NSString *msg = nil;
BOOL isSave;
if(error != NULL) {
msg = @"保存失败!" ;
isSave = NO;
}
else {
msg = @"保存成功!" ;
isSave = YES;
}
///代理回调
[_delegate isSaveImage:image didFinishSavingWithError:error contextInfo:contextInfo];
}
@end
4.获取UIView的截图
//
// UIView+Screenshots.h
// Runner
//
// Created by macmini on 2020/9/16.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
///截图类
@interface UIView (Screenshots)
/**
普通的截图
该API仅可以在未使用layer和OpenGL渲染的视图上使用
@return 截取的图片
*/
- (UIImage *)nomalSnapshotImage;
/**
针对有用过OpenGL渲染过的视图截图
@return 截取的图片
*/
- (UIImage *)openglSnapshotImage;
/**
截图
以UIView 的形式返回(_UIReplicantView)
@return 截取出来的图片转换的视图
*/
- (UIView *)snapshotView;
@end
NS_ASSUME_NONNULL_END
//
// UIView+Screenshots.m
// Runner
//
// Created by macmini on 2020/9/16.
//
#import "UIView+Screenshots.h"
@implementation UIView (Screenshots)
/**
普通的截图
该API仅可以在未使用layer和OpenGL渲染的视图上使用
@return 截取的图片
*/
- (UIImage *)nomalSnapshotImage
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
/**
针对有用过OpenGL渲染过的视图截图
@return 截取的图片
*/
- (UIImage *)openglSnapshotImage
{
CGSize size = self.bounds.size;
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
CGRect rect = self.frame;
[self drawViewHierarchyInRect:rect afterScreenUpdates:YES];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
/**
截图
以UIView 的形式返回(_UIReplicantView)
@return 截取出来的图片转换的视图
*/
- (UIView *)snapshotView
{
UIView *snapView = [self snapshotViewAfterScreenUpdates:YES];
return snapView;
}
@end
5.获取UIWebView的截图
//
// UIWebView+Screenshots.h
// Runner
//
// Created by macmini on 2020/9/16.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
///截图
@interface UIWebView (Screenshots)
///UIWebView截图
- (UIImage *)imageForWebView;
@end
NS_ASSUME_NONNULL_END
//
// UIWebView+Screenshots.m
// Runner
//
// Created by macmini on 2020/9/16.
//
#import "UIWebView+Screenshots.h"
@implementation UIWebView (Screenshots)
///UIWebView截图
- (UIImage *)imageForWebView
{
// 1.获取WebView的宽高
CGSize boundsSize = self.bounds.size;
CGFloat boundsWidth = boundsSize.width;
CGFloat boundsHeight = boundsSize.height;
// 2.获取contentSize
CGSize contentSize = self.scrollView.contentSize;
CGFloat contentHeight = contentSize.height;
// 3.保存原始偏移量,便于截图后复位
CGPoint offset = self.scrollView.contentOffset;
// 4.设置最初的偏移量为(0,0);
[self.scrollView setContentOffset:CGPointMake(0, 0)];
NSMutableArray *images = [NSMutableArray array];
while (contentHeight > 0) {
// 5.获取CGContext 5.获取CGContext
UIGraphicsBeginImageContextWithOptions(boundsSize, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 6.渲染要截取的区域
[self.layer renderInContext:ctx];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 7.截取的图片保存起来
[images addObject:image];
CGFloat offsetY = self.scrollView.contentOffset.y;
[self.scrollView setContentOffset:CGPointMake(0, offsetY + boundsHeight)];
contentHeight -= boundsHeight;
}
// 8 webView 恢复到之前的显示区域
[self.scrollView setContentOffset:offset];
CGFloat scale = [UIScreen mainScreen].scale;
CGSize imageSize = CGSizeMake(contentSize.width * scale,
contentSize.height * scale);
// 9.根据设备的分辨率重新绘制、拼接成完整清晰图片
UIGraphicsBeginImageContext(imageSize);
[images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger idx, BOOL *stop) {
[image drawInRect:CGRectMake(0,scale * boundsHeight * idx,scale * boundsWidth,scale * boundsHeight)];
}];
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return fullImage;
}
@end