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

基于C#在WPF中使用斑马打印机进行打印

 最近在项目中接手了一个比较有挑战性的模块——用斑马打印机将需要打印的内容打印出来。苦苦折腾了两天,总算有所收获,就发到网上来骗骗分数-_-||

    项目中使用的打印机型号为GX430t的打印机,接手的时候,自己对于打印机这块儿是眼前一抹黑,啥都不知道。没办法一步步来。

    首先尝试使用WPF中的PrintDialog里面的PrintVisual和PrintDocument方法,打印机是一点反应都没有,最后得到的结论是:斑马打印机不支持MS的XPS文档格式,所以使用WPF来排版后进行驱动打印就不要想了,不可能!!!这条路到这里就断了。

    然后就想到有没有SDK可以直接进行打印,就找到了斑马打印机的技术支持,还是个妹子,我提了一下,妹子说没有开发包可以用,然后就贴了一个网址给我,网址就是这条:C#调用斑马打印机打印条码标签(含源码)(支持COM、LPT、USB、TCP连接方式和ZPL、EPL、CPCL指令)_c#控制斑马zebra打印机源码-CSDN博客。可能我的水平有限,反正我感觉啰啰嗦嗦一大堆,实际的东西没多少,不过关键点倒是提了出来使用图像或者指令进行打印。我首先想到的是使用指令进行打印,就去找妹子要了Zebra的技术手册,一打开就吓尿了,尼玛1000+页的东西,我只是用一下打印机又不是去帮你们打印机开发驱动,当时心里那个抵触啊。但是没办法,得看呐,就仔细看了一些,找到打印的指令试了试,有东西能打出来,当时感觉挺满足的。唯一比较纠结的就是打印机支持的字体和字体本身的一些设置,比如粗体、斜体等等,资料里面没找到,然后去问了下斑马的技术支持,得知斜体字可以打,但是不清楚有没有对应的指令。没办法,项目里面用的字体多,还有各种斜体神马的,玩WPF的都知道,那么多属性一个个设置下来,光字体类型斑马就搞不定。

    既然直接使用指令打印行不通就考虑使用图像打印,图像又跟多媒体挂钩了,尼玛真是够了。因为玩过链接里面的仁兄提到的获取打印模板的命令的方法。就是在安装好打印机驱动后,手动创建一个新的本地端口并在打印机设置中将打印机端口设为新建的端口。使用Zebra的创建模板的软件创建好你想要的东西,然后打印,就能在你创建的端口文件中得到你想要的指令序列(其实,模板里面使用的就是图像打印)。指令序列有了,对照手册查询相应的指令就能得到你想要的东西。

    这里说的图像打印并不是我们平时说的位图或者矢量图,手册里面说是叫GRF格式的图像,仔细研究了一下,其实就是缀着这么个名字而已,里面需要的数据其实就是图像矩阵。而且图像矩阵中的像素表示法是:一个字节表示8个像素,也就是一个bit位(0或1)表示一个像素的颜色(黑或白)。看到这里脑子里有了思路:将要打印的内容进行排版->将排版好的数据转换成位图->将位图中的数据,根据需要转换成指令中要求的格式->交给打印机打印。这样一来就没有什么打印机对字体本身的限制了。思路有了,剩下的就是方法。

    排版比较简单,这个玩过自定义控件的人都知道,使用DrawingVisual可以构建自己想要的Visual。然而将Visual转换成位图就难住我了,纠结了一个下午终于从网上找到了一个东西----RenderTargetBitmap。这个类可以将你的Visual转换成位图。

    下面就是将位图数据转换成指令中的图像数据,咳咳,数学不够好,在分析数据的时候搞错了一个地方让我纠结了好长时间,不过总体来说还是解决了。说一下思路:

  1. 通过RenderTargetBitmap类的CopyPixels方法将像素数据拷贝出来。因为这个位图创建的时候只是作为一个中间的过程,所以格式可以随便选,我是选择了PixelFormats.Pbgra32格式,比较简单。这个格式的图像像素是用4个字节表示,依次为:Blue、Green、Red、Alpha。拷贝的时候,作为缓冲区的数组需要将长度设为像素数的4倍。
  2. 像素拷贝的时候会有一个“跨距”的东西。这个表示的是图像中一行中数据的字节数,必须为4的倍数。也就是取大于或等于真实值的最小的能够被4整除的数值。
  3. 获取到数据就可以对数据进行整理了,遍历整个数组,如果当前像素的颜色值不为白色或者透明色就将目标数组中的bit位之一(目标数组中用bit位表示对应像素的值)
  4. 将获得的数组转换成string串,然后将该串插入到指令序列中相应的位置就得到对应的指令。

    说到这里其实说的也差不多了,顺便说下,WPF里面的打印支持真的很强大,给打印机传递指令的操作也很简单,具体见下面的代码。

这里是源代码:

        /// <summary>
        /// 获取绘制Visual的命令
        /// </summary>
        /// <param name="visual">要获取的Visual</param>
        /// <param name="pixelWidth">像素宽度</param>
        /// <param name="pixelHeight">像素高度</param>
        /// <param name="dpiX">横向dpi</param>
        /// <param name="dpiY">纵向dpi</param>
        /// <param name="offsetX">横坐标偏移量,单位为像素数</param>
        /// <param name="offsetY">纵坐标偏移量,单位为像素数</param>
        /// <returns></returns>
        private string GetPrintZPL(Visual visual, int pixelWidth, int pixelHeight, double dpiX, double dpiY, int offsetX, int offsetY)
        {
            string ret = string.Empty;
            //构建图片
            RenderTargetBitmap bmp = new RenderTargetBitmap(pixelWidth, pixelHeight, dpiX, dpiY, PixelFormats.Pbgra32);
#if TEST //test
            DrawingVisual newVisual = new DrawingVisual();
            DrawingContext dc = newVisual.RenderOpen();
            dc.DrawEllipse(Brushes.Black, new Pen(), new Point(bmp.Width / 2, bmp.Height / 2), bmp.Width / 2, bmp.Height / 2);
            dc.Close();
            visual = null;
            bmp.Render(newVisual);
#else
            bmp.Render(visual);
#endif
            byte[] datas = new byte[bmp.PixelWidth * bmp.PixelHeight * 4];
            bmp.CopyPixels(datas, bmp.PixelWidth * 4, 0);//获取图像数据
            int rowBytes = (pixelWidth + 7) / 8;
            byte[] targetDatas = new byte[rowBytes * bmp.PixelHeight];
            for (int i = 0; i < bmp.PixelHeight; i++) //数据调整,并将数据
            {
                for (int j = 0; j < bmp.PixelWidth; j++)
                {
                    byte blue = datas[i * bmp.PixelWidth * 4 + j * 4 + 0];
                    byte green = datas[i * bmp.PixelWidth * 4 + j * 4 + 1];
                    byte red = datas[i * bmp.PixelWidth * 4 + j * 4 + 2];
                    byte alpha = datas[i * bmp.PixelWidth * 4 + j * 4 + 3];
                    if (blue == 0 && green == 0 && red == 0)
                    {
                        if (alpha == 255)//alpha也是0则为透明色
                        {
                            byte cur = 1;
                            cur = (byte)(cur << (7 - j % 8));
                            targetDatas[i * rowBytes + j / 8] |= cur;
                        }
                    }
                    else
                    {
                        if (!(blue == 255 && green == 255 && red == 255 && alpha == 255))//全为255则表示白色
                        {
                            byte cur = 1;
                            cur = (byte)(cur << (7 - j % 8));
                            targetDatas[i * rowBytes + j / 8] |= cur;
                        }
                    }
                }
            }
            ret = string.Format("^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR3,3~SD29^JUS^LRN^CI0^XZ~DG000.GRF,{0},{1},{2}^XA^MMT^PW260^LL0189^LS0^FT0,192^FO{3},{4},^XG000.GRF,1,1^FS^PQ1,0,1,Y^XZ^XA^ID000.GRF^FS^XZ", targetDatas.Length, rowBytes, BitConverter.ToString(targetDatas).Replace("-", string.Empty), offsetX, offsetY);
            return ret;
        }

相关文章:

基于C#在WPF中使用斑马打印机进行打印

最近在项目中接手了一个比较有挑战性的模块——用斑马打印机将需要打印的内容打印出来。苦苦折腾了两天&#xff0c;总算有所收获&#xff0c;就发到网上来骗骗分数-_-|| 项目中使用的打印机型号为GX430t的打印机&#xff0c;接手的时候&#xff0c;自己对于打印机这块儿是眼前…...

六、资产安全—信息分级资产管理与隐私保护练习题(CISSP)

六、资产安全—信息分级资产管理与隐私保护(CISSP): 六、资产安全—信息分级资产管理与隐私保护(C...

使用 AutoGen 的 AI 智能体设计模式

1.Auto Gen框架 在Auto中,每种智能体分别扮演不同的角色。 ConversableAgent 作为最高级别的智能体抽象,为所有具体智能体提供了基础的通信能力。这包括发送和接收信息的能力,以及基于这些信息进行内部状态更新的能力。所有从这个类派生的智能体都继承了这些基本功能…...

Android InputChannel连接

InputChannel是InputDispatcher 和应用程序 (InputTarget) 的通讯桥梁&#xff0c;InputDispatcher 通知应用程序有输入事件&#xff0c;通过InputChannel中的socket进行通信。 连接InputDispatcher和窗口 WinodwManagerService:addwindow: WMS 添加窗口时&#xff0c;会创建…...

爬虫笔记17——selenium框架的使用

selenium框架的使用 1、python程序安装selenium框架2、下载Chrome谷歌驱动3、selenium的基本使用4、多个标签页切换顺序混乱的问题 1、python程序安装selenium框架 # 在安装过程中最好限定框架版本为4.9.1 # pip install selenium 没有制定版本&#xff0c;非镜像下载也会比较…...

[BUUCTF从零单排] Web方向 02.Web入门篇之『常见的搜集』解题思路(dirsearch工具详解)

这是作者新开的一个专栏《BUUCTF从零单排》&#xff0c;旨在从零学习CTF知识&#xff0c;方便更多初学者了解各种类型的安全题目&#xff0c;后续分享一定程度会对不同类型的题目进行总结&#xff0c;并结合CTF书籍和真实案例实践&#xff0c;希望对您有所帮助。当然&#xff0…...

深度相机识别物体——实现数据集准备与数据集分割

一、数据集准备——Labelimg进行标定 1.安装labelimg——pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple 2.建立相应的数据集存放文件夹 3.打开labelimg&#xff0c;直接在命令行输入labelimg即可&#xff0c;并初始化 4.开始标注&#xff0c;设置标注好…...

STM32第十一课:ADC采集光照

文章目录 需求一、ADC概要二、实现流程1.开时钟&#xff0c;分频&#xff0c;配IO2.配置ADC工作模式3.配置通道4.复位校准5.数值的获取 三、需求的实现总结 需求 通过ADC转换实现光照亮度的数字化测量&#xff0c;最后将实时测量的结果打印在串口上。 一、ADC概要 ADC全称是A…...

python查找支撑数 青少年编程电子学会python编程等级考试三级真题解析2022年3月

目录 python查找支撑数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python查找支撑数 2022年3月 python编程等级考试级编程题 一、题目要求…...

创建一个快速、高效的网络爬虫:PHP和Selenium示例

随着互联网的不断发展&#xff0c;数据爬取已经成为了许多人的必备技能。而网络爬虫则是实现数据爬取的重要工具之一。 网络爬虫可以自动化地访问网站、获取内容、分析页面并提取所需数据。其中&#xff0c;Selenium是一款非常优秀的网络自动化测试工具&#xff0c;能够模拟真…...

两张图片怎样拼在一起?将两张图片拼在一起的几种方法介绍

两张图片怎样拼在一起&#xff1f;拼接两张图片是一种常见的编辑技巧&#xff0c;能够将不同的视觉元素融合成一个整体&#xff0c;从而创造出更加生动和丰富的图像效果。无论是为了设计创意作品、制作社交媒体内容&#xff0c;还是简单地为个人相册增添趣味&#xff0c;掌握如…...

百日筑基第五天-关于maven

百日筑基第五天-关于maven Maven 是什么 Maven 是一个项目管理工具&#xff0c;它包含了一个项目对象模型&#xff08;Project Object Model&#xff09;&#xff0c;反映在配置中&#xff0c;就是一个 pom.xml 文件。是一组标准集合&#xff0c;一个项目的生命周期、一个依赖…...

【CSS in Depth 2 精译】2.2 em 和 rem + 2.2.1 使用 em 定义字号

当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力 2.1.1 响应式设计的兴起 2.2 em 与 rem ✔️ 2.2.1 使用 em 定义字号 ✔️2.2.2 使用 rem 设置字号 2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高2.6 自定义属性2.7 本章小结 2.…...

C++Primer Plus 第十四章代码重用:14.4.4 数组模板示例和非类型参数

系列文章目录 14.4.4 数组模板示例和非类型参数 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 系列文章目录14.4.4 数组模板示例和非类型参数 14.4.4 数组模板示例和非类型参数 模板常用作容器类&#xff0c;这…...

短视频哪个软件好用?成都柏煜文化传媒有限公司

短视频哪个软件好用&#xff1f;一文带你了解各大平台特色 随着移动互联网的飞速发展&#xff0c;短视频已经成为现代人生活中不可或缺的一部分。市面上涌现出众多短视频平台&#xff0c;它们各具特色&#xff0c;满足了不同用户的需求。那么&#xff0c;短视频哪个软件好用呢…...

金融科技:重塑用户体验,驱动满意度飙升

随着科技的飞速发展&#xff0c;金融科技&#xff08;FinTech&#xff09;已经深入到我们生活的每一个角落&#xff0c;从日常支付到投资理财&#xff0c;再到跨境汇款&#xff0c;它都在悄无声息地改变着我们的金融行为。而在这背后一个不可忽视的驱动力就是金融科技对用户体验…...

JavaScript——算术运算符

目录 任务描述 相关知识 - * / %运算符 递增运算符和递减运算符 编程要求 任务描述 本关任务&#xff1a;给定两个字符串变量&#xff0c;把它们转为数字后相除&#xff0c;拼接被除数、除数和余数为一个新的字符串。 例如&#xff1a;a 为 "5"&#xff0c;b 为…...

备份SQL Server数据库并还原到另一台服务器

我可以将SQL Server数据库备份到另一台服务器吗&#xff1f; 有时您可能希望将 SQL数据库从一台服务器复制到另一台服务器&#xff0c;或者将计算机复制到计算机。可能的场景包括测试、检查一致性、从崩溃的机器恢复数据库、在不同的机器上处理同一个项目等。 是的&#xff0c…...

二刷算法训练营Day45 | 动态规划(7/17)

目录 详细布置&#xff1a; 1. 139. 单词拆分 2. 多重背包理论基础 3. 背包总结 3.1 背包递推公式 3.2 遍历顺序 01背包 完全背包 详细布置&#xff1a; 1. 139. 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单…...

大模型项目落地时,该如何估算模型所需GPU算力资源

近期公司有大模型项目落地。在前期沟通时,对于算力估算和采购方案许多小伙伴不太了解,在此对相关的算力估算和选择进行一些总结。 不喜欢过程的可以直接 跳到HF上提供的模型计算器 要估算大模型的所需的显卡算力,首先要了解大模型的参数基础知识。 大模型的规模、参数的理解…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...