当前位置: 首页 > article >正文

【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,把想要打印的界面打印成图片

【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,打印想打印的界面

设备/引擎:Mac(14.1.1)/cocos

开发工具:Xcode

开发语言:OC/C++

开发需求:工程中需要为用户提供一个打印功能,让用户可以随时打印自己想要打印的界面

APP属于iOS工程,所以打印代码考虑直接用OC代码调用iOS原生界面就可以,很好用,也不用自己去写UI,也比较适合短周期开发的情况,话不多说,直接正文

1.打印代码
大致过程是这样的,OC代码判断获取到的图片信息是否合法,再调用iOS原生的打印控制器,判断是否有可用的打印机,最后用户点击打印即可……
获取图像部分

    @autoreleasepool {// 获取 Document 路径NSString* docsDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;NSString* imagePath = [docsDir stringByAppendingPathComponent:[NSString stringWithUTF8String:filename]];UIImage* image = [UIImage imageWithContentsOfFile:imagePath];if (!image) {NSLog(@"[PrintHelper] 图片未找到:%@", imagePath);return;}.........

Tips:整段代码用autoreleasepool包裹起来可以让其中的临时对象在代码块结束后及时释放,避免内存泄露

判断打印控制器是否可用并设置打印内容

        UIPrintInteractionController* printController = [UIPrintInteractionController sharedPrintController];if (!printController || ![UIPrintInteractionController canPrintData:UIImagePNGRepresentation(image)]) {NSLog(@"[PrintHelper] 当前设备无法打印图片。");return;}printController.printingItem = image; //设置打印内容

异步显示iOS原生打印对话框

dispatch_async(dispatch_get_main_queue(), ^{

弹出打印界面 + 打印结果回调

[printController presentAnimated:YES completionHandler:^(UIPrintInteractionController * _Nonnull controller, BOOL completed, NSError * _Nullable error) {if (error) {NSLog(@"[PrintHelper] 打印失败:%@", error.localizedDescription);} else if (completed) {NSLog(@"[PrintHelper] 打印完成。");} else {NSLog(@"[PrintHelper] 用户取消打印。");}
}];

至此iOS原生打印代码就算完成了

2.获取打印图片代码
这个就是你想打印的部分,我们的工程中涉及打印的就是涂色相关的玩法,所以有两种方法可以获取打印区域,一种是获取你需要打印的多个画布,将这些画布内容渲染出来保存为图片文件再打印;还有一种方法是直接对屏幕内容进行局部截图处理,将截好的图直接传过去进行打印
1)获取多个画布节点,将他们都渲染到一张新画布上,然后再打印出来
创建画布

   // 1. 创建一张足够大的 renderTextureCCSize targetSize = CCSizeMake(winSize.width, winSize.height); // 设置尺寸CCRenderTexture* rt = CCRenderTexture::create(targetSize.width, targetSize.height);rt->beginWithClear(1,1,1,1);  // 白底

获取多张ColoringClippingNode画布并渲染

   for (int i = 0; i < m_ClipDrawArray->count(); i++) {ColoringClippingNode* clip = (ColoringClippingNode*)m_ClipDrawArray->objectAtIndex(i);if (!clip) continue;// 保存原始位置CCPoint oldClipPos = clip->getPosition();// 计算偏移,使其居中绘制CCPoint centeredPos = ccp(winSize.width/2, winSize.height/2);if(i==0){clip->setPosition(ccp(winSize.width*0.65, winSize.height/2));}else{clip->setPosition(centeredPos);}// 直接visit整个clip节点,节点上的遮罩也会生效clip->visit();// 恢复原始位置clip->setPosition(oldClipPos);}

如果有需要渲染的sprite精灵也需要加进来

   auto sprite = whiteCanvas;if (sprite){// 保存auto oldA = sprite->getAnchorPoint();auto oldP = sprite->getPosition();// 设置锚点和位置到大图中心sprite->setAnchorPoint(ccp(0.5f,0.5f));sprite->setPosition(ccp(targetSize.width/2, targetSize.height/2));sprite->visit();// 恢复sprite->setAnchorPoint(oldA);sprite->setPosition(oldP);}

都渲染之后就是结束画布渲染

   rt->end();

保存渲染好的画布;调用打印代码

 rt->saveToFile("printScene.png", kCCImageFormatPNG);  //将画布保存为PNG并命名
// 延迟调用打印代码,避免未渲染保存就打印CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(ColorCanvasView::callPrintImage),this, 0, 0, 0.3f, false);

以上就是通过将多张画布及精灵渲染到一张画布再保存成文件,最后打印的过程,下面再说说如何通过截屏操作来打印

2)对屏幕想要打印的区域进行截屏保存,再打印
截屏代码

   @autoreleasepool {// 获取根控制器和屏幕信息AppController *app = (AppController *)[UIApplication sharedApplication].delegate;UIViewController *viewController = [app viewController];UIView *targetView = viewController.view;CGFloat scale = [UIScreen mainScreen].scale;CGSize viewSize = targetView.bounds.size;
        // 1. 截屏UIGraphicsBeginImageContextWithOptions(viewSize, NO, scale);[targetView drawViewHierarchyInRect:CGRectMake(0, 0, viewSize.width, viewSize.height) afterScreenUpdates:YES];UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();if (!fullImage) {NSLog(@"截屏失败");return;}
        // 2. 裁剪区域CGRect cropRect = CGRectMake(x * scale, y * scale, width * scale, height * scale);CGImageRef croppedCGImage = CGImageCreateWithImageInRect(fullImage.CGImage, cropRect);if (!croppedCGImage) {NSLog(@"裁剪失败");return;}UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImagescale:scaleorientation:fullImage.imageOrientation];CGImageRelease(croppedCGImage);CGSize targetSize = CGSizeMake(width, height);UIGraphicsBeginImageContextWithOptions(targetSize, NO, scale);

一般还是需要对截屏区域进行缩放,保证打印时图像大小位置合适
缩放居中代码

        CCSize winSizes = GameManager::sharedManager()->getViewVisibleSize();// 4. 缩放CGFloat shrinkScale = 0.85;CGFloat offX_x=0.3;CGSize scaledSize = CGSizeMake(croppedImage.size.width * shrinkScale, croppedImage.size.height * shrinkScale);// 5. 计算居中位置CGPoint origin = CGPointMake((targetSize.width - scaledSize.width) *offX_x, (targetSize.height - scaledSize.height) / 2.0);// 6. 居中绘制缩小后的图像[croppedImage drawInRect:CGRectMake(origin.x, origin.y, scaledSize.width, scaledSize.height)];// 7. 得到最终图像UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();

最后就是将图像保存为文件

        // 8. 保存图像到文件NSData *imageData = UIImagePNGRepresentation(finalImage);if (!imageData) {NSLog(@"图片数据为空");return;}NSString *docsDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;NSString *imagePath = [docsDir stringByAppendingPathComponent:[NSString stringWithUTF8String:filename]];if ([imageData writeToFile:imagePath atomically:YES]) {NSLog(@"图片保存成功:%@", imagePath);} else {NSLog(@"图片保存失败");}

以上就是如何通过OC代码来进行截屏操作,接下来就是在工程中如何调用

    float x = winSize.width*widthX_x; // 起始横坐标(point)float y = winSize.height*heightOffY; // 起始纵坐标(point)float w = winSize.width*widthOffX; // 宽度float h = winSize.height; // 高度const char* filename = "printScene.png";DeviceManager::sharedManager()->printSceneAddedToFile(filename, x, y, w, h);
// 延迟调用打印代码,避免未渲染保存就打印CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(ColorCanvasView::callPrintImage),this, 0, 0, 0.3f, false);

以上就是如何通过截屏保存图片最后打印

上面两种方法都可以实现打印指定区域的效果,具体实现可以根据自身的项目需求来定

希望能给大家带来帮助!!!有什么问题不明白的需要讨论的都可以评论私信欢迎一起讨论~~~

相关文章:

【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,把想要打印的界面打印成图片

【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能&#xff0c;连接本地打印机&#xff0c;打印想打印的界面 设备/引擎&#xff1a;Mac&#xff08;14.1.1&#xff09;/cocos 开发工具&#xff1a;Xcode 开发语言&#xff1a;OC/C 开发需求&#xff1a;工程中…...

随记 配置服务器的ssl整个过程

第一步 先了解到这个公钥私钥服务器自己可以生成&#xff0c;但是没什么用&#xff0c;浏览器不会信任的&#xff0c;其他人访问不了。所以要一些中间机构颁布的证书才有用。 一般的服务器直接 安装 Certbot 和插件 //CentOS Nginx 用户&#xff1a; sudo yum install epe…...

数据库高可用架构设计:集群、负载均衡与故障转移实践

关键词:数据库高可用,HA架构,数据库集群,负载均衡,故障转移,SQL Server Always On,MySQL InnoDB Cluster,高可用性组,读写分离,灾难恢复 在当今瞬息万变的数字化时代,数据的价值日益凸显,数据库作为承载核心业务数据的基石,其可用性直接决定了业务的连续性与用户…...

Correlations氛围测试:文本或图像的相似度热图

1 项目概览:Correlations 是什么? Correlations 是一个交互式 UI 工具,Jina AI 开源项目 Correlations 用于调试和可视化文本或图像向量之间的相似性关系,特别适合:快速把相关内容两两对照,比单纯数字报告更直观。Correlations 把这种快速、主观“氛围检视”做成了可视化…...

从0到1:多医院陪诊小程序开发笔记(上)

概要设计 医院陪诊预约小程序&#xff1a;随着移动互联网的普及&#xff0c;越来越多的医院陪诊服务开始向线上转型, 传统的预约方式往往效率低下&#xff0c;用户需耗费大量时间进行电话预约或现场排队&#xff0c;陪诊服务预约小程序集多种服务于一体&#xff0c;可以提高服…...

建立连接后 TCP 请求卡住

大家读完觉得有意义记得关注和点赞&#xff01;&#xff01;&#xff01; 这篇文章描述了一个内核和BPF网络问题 以及故障排除步骤&#xff0c;这是一个值得深入研究的有趣案例 Linux 内核网络复杂性。 目录 1 故障报告 1.1 现象&#xff1a;概率健康检查失败 1.2 范围&am…...

尚硅谷redis7 99 springboot整合redis之连接集群

6381宕机&#xff0c;手动shutdown后在redis中&#xff0c;634自动上位变成master结点。 但是在springboot中却没有动态感知道redisCluster的最新集群消息&#xff0c;所以找不到我们要检索的数据。原因是&#xff1a;SpringBoot 2.X版本,Redis默认的连接池采用 Lettuce&#…...

hive 笔记

1. 查看hive表的文件情况 搭建ui界面机器上查看 show create table xxx;得到文件地址 hdfs查看文件情况 hdfs dfs -ls hdfs://HDFS4005133/usr/hive/warehouse/xxx/xxxx/app_idxxx...

无线通信模块简介

QuecPython 是运行在无线通信模块上的开发框架。对于首次接触物联网开发的用户而言&#xff0c;无线通信模块可能是一个相对陌生的概念。本文主要针对无线通信和蜂窝网络本身&#xff0c;以及模块的概念、特性和开发方式进行简要的介绍。 无线通信和蜂窝网络 物联网对无线通信…...

Go语言之空接口与类型断言

Go 语言中&#xff0c;接口是一种强大的抽象机制。其中&#xff0c;空接口&#xff08;interface{}&#xff09;和类型断言为我们提供了处理任意类型与类型检查的能力。 一、空接口&#xff08;interface{}&#xff09; 空接口是 Go 中最特殊的接口&#xff1a;不包含任何方法…...

把 CURSOR 的工具活动栏改成和 VSCODE 一样的左侧展示

目前使用cursor的时候发现工具栏与vscode的布局不一致&#xff0c;cursor在顶部导致操作起来不方便&#xff0c;如何改成与vscode相同的左侧布局展示。 解决方案 文件→首选项→设置&#xff0c;进入设置中&#xff0c;然后点击这个icon图标&#xff0c;可以打开配置文件 se…...

碰一碰系统源码搭建==saas系统

搭建“碰一碰”系统&#xff08;通常指基于NFC或蓝牙的短距离交互功能&#xff09;的源码实现&#xff0c;需结合具体技术栈和功能需求。以下是关键步骤和示例代码&#xff1a; 技术选型 NFC模式&#xff1a;适用于Android/iOS设备的近场通信&#xff0c;需处理NDEF协议。蓝牙…...

不加载PHP OpenTelemetry SDK实现Trace‌与Logs

目录 前言一、回到OpenTelemetry原理看问题1、数据接收&#xff08;Receivers&#xff09;2、数据处理&#xff08;Processors&#xff09;3、数据导出&#xff08;Exporters&#xff09; 二、不加载OpenTelemetry SDK实现Trace‌与Logs示例 前言 前面两篇我们分别介绍了OpenT…...

Three.js搭建小米SU7三维汽车实战(6)颜色切换

颜色切换 接下来我们来实现懂车帝的颜色切换效果 可以让ai帮我们生成页面结构以及样式&#xff0c;注意changeCarBodyColor这个函数需要我们自己来写 // 创建颜色选择器UI function createColorSelector() {const colors [{ name: "深海蓝", hex: "#1A9CB0&qu…...

mysql慢sql的实际处理方案之一

复习mysql架构图 当大批量慢sql过来&#xff0c;显然就是占用了线程池的链接&#xff0c;然后长久不释放&#xff0c;所以会出现线程池满的问题&#xff0c;致使正常业务sql也全部阻塞&#xff0c;影响整个业务。 AI搜索如下&#xff1a; 可以考虑一种方案&#xff1a; 将线…...

GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【六】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…...

c/c++的opencv车牌识别

OpenCV 安装&#xff1a; 你需要正确安装 OpenCV 库。Tesseract OCR 安装&#xff1a; 你需要安装 Tesseract OCR 引擎。在 Ubuntu/Debian 上&#xff0c;可以使用&#xff1a;sudo apt-get install tesseract-ocr sudo apt-get install libtesseract-dev sudo apt-get install…...

4.2.3 Spark SQL 手动指定数据源

在本节实战中&#xff0c;我们学习了如何在Spark SQL中手动指定数据源以及如何使用format()和option()方法。通过案例演示&#xff0c;我们读取了不同格式的数据文件&#xff0c;包括CSV、JSON&#xff0c;并从JDBC数据源读取数据&#xff0c;展示了如何将这些数据转换为DataFr…...

【论文解读】CVPR2023 PoseFormerV2:3D人体姿态估计(附论文地址)

论文链接&#xff1a;https://arxiv.org/pdf/2303.17472 源码链接&#xff1a;https://github.com/QitaoZhao/PoseFormerV2 Abstract 本文提出了 PoseFormerV2&#xff0c;通过探索频率域来提高 3D 人体姿态估计的效率和鲁棒性。PoseFormerV2 利用离散余弦变换&#xff08;DC…...

WPF的交互核心:命令系统(ICommand)

命令系统&#xff08;ICommand&#xff09; 1 RelayCommand实现2 CanExecute控制按钮可用性3 参数传递&#xff08;CommandParameter&#xff09;3.1 静态参数绑定&#xff1a;3.2 动态参数绑定&#xff1a;3.3 复杂对象参数&#xff1a; 4 异步命令实现5 常见问题排查 WPF的命…...

Maven工程演示

软件&#xff1a;idea 一、项目创建 操作截图file -> New -> Projectnextnext -> Name:工程名称&#xff1b;Location:项目路径&#xff1b;项目创建完成;文件夹基本样例&#xff1a;&#xff08;如果不完整自己创建即可&#xff09;MANIFEST.MF内容 二、导入依赖 …...

uniapp分包配置,uniapp设置subPackages

在使用uniapp开发过程中&#xff0c;由于项目比较大&#xff0c;无法直接上传&#xff0c;需要分包后才可以上传。 步骤&#xff1a; 1、在pages同级目录下创建分包的目录&#xff08;pages_second&#xff09;&#xff0c;把要分包的文件放到该目录下&#xff1b; 2、在pag…...

计算机网络 HTTP篇常见面试题总结

HTTP各版本区别 HTTP 1.0 无状态、无连接&#xff1a;每次请求都需要建立新的 TCP&#xff0c;处理完后立即关闭&#xff0c;导致开销较大。队头阻塞&#xff1a;每个请求必须按照顺序依次处理&#xff0c;前面的请求未完成&#xff0c;后面的请求只能等待&#xff0c;减低了…...

C++八股 —— 手撕线程池

文章目录 一、背景二、线程池实现1. 任务队列和工作线程2. 构造和析构函数3. 添加任务函数4. 完整代码 三、阻塞队列实现1. 基础队列2. 升级版队列 四、测试代码五、相关问题六、其他实现方式 来自&#xff1a;华为C一面&#xff1a;手撕线程池_哔哩哔哩_bilibili 华为海思&am…...

RPA如何支持跨平台和跨浏览器的自动化

RPA&#xff0c;即机器人流程自动化&#xff08;Robotic Process Automation&#xff09;&#xff0c;正日益成为企业实现业务流程高效自动化的关键技术。在复杂的数字化环境中&#xff0c;跨平台和跨浏览器的自动化需求极为迫切&#xff0c;RPA 通过多种技术手段和策略来满足这…...

【笔记】Windows 成功部署 Suna 开源的通用人工智能代理项目部署日志

#工作记录 本地部署运行截图 kortix-ai/suna&#xff1a; Suna - 开源通用 AI 代理 项目概述 Suna 是一个完全开源的 AI 助手&#xff0c;通过自然对话帮助用户轻松完成研究、数据分析等日常任务。它结合了强大的功能和直观的界面&#xff0c;能够理解用户需求并提供结果。其强…...

关于ffplay在macos上运行奔溃的问题

这个问题大概是由于 MacOS 的问题引起的&#xff0c;奔溃的地方在 SDL2 的代码中&#xff0c;如果直接使用 brew 安装 SDL2就会遇到这个问题&#xff0c;所以需要修改 SDL2源码然后再编译安装。 我这里采用的是 origin/release-2.28.x 分支&#xff0c;修改部分如下&#xff1…...

Linux531rsync定时同步 再回忆

rsync定时同步 环境配置 关闭防火墙&#xff0c;selinux systemctl stop firewalld systemctl disable firewall setenforce 0 cat /etc/selinux/configpei SELINUXdisable设置主机名 systemctl set-hostname code systemctl set-hostname backup设置静态IP rsync由于要设…...

Elasticsearch 分析器介绍

在 Elasticsearch 的世界里,构建高效搜索引擎的关键一环,便是透彻理解分析器(Analyzer)的工作机制。一个优秀的搜索引擎,能够精准地返回与用户查询紧密相关的文档,而这背后,正是分析器在默默发挥着核心作用。它不仅负责处理待索引的文档,还在用户发起查询时,智能评估哪…...

【KWDB 创作者计划】_探秘浪潮KWDB数据库:从时间索引到前沿技术

探秘浪潮KWDB数据库&#xff1a;从时间索引到前沿技术 文章目录 探秘浪潮KWDB数据库&#xff1a;从时间索引到前沿技术引言1.浪潮KWDB数据库时间索引深度解析1.1时间索引工作原理1.2时间索引创建与管理实践 2.浪潮KWDB数据库前沿产品技术纵览2.1多模融合存储引擎2.2就地计算技术…...