当前位置: 首页 > 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上提供的模型计算器 要估算大模型的所需的显卡算力,首先要了解大模型的参数基础知识。 大模型的规模、参数的理解…...

LLM应用开发-RAG系统评估与优化

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;在上一篇文章中&#xff0c;我们学习了如何基于LangChain构建RAG应用&#xff0c;并且通过Streamlit将这个RAG应用部署到了阿里云服务器&#xff1b;&am…...

秋招突击——第七弹——Redis快速入门

文章目录 引言Redis是什么 正文对象String字符串面试重点 List面试考点 压缩列表ZipList面试题 Set面试题讲解 Hash面试重点 HASHTABLE底层面试考点 跳表面试重点 ZSET有序链表面试重点 总结 引言 在项目和redis之间&#xff0c;我犹豫了一下&#xff0c;觉得还是了解学习一下…...

软考初级网络管理员__操作系统单选题

1.在Windows资源管理器中&#xff0c;假设已经选定文件&#xff0c;以下关于“复制”操作的叙述中&#xff0c;正确的有()。 按住Ctr键&#xff0c;拖至不同驱动器的图标上 按住AIt键&#xff0c;拖至不同驱动器的图标上 直接拖至不同驱动器的图标上 按住Shift键&#xff0…...

从入门到精通:网络编程套接字(万字详解,小白友好,建议收藏)

一、预备知识 1.1 理解源IP地址和目的IP地址 在网络编程中&#xff0c;IP地址&#xff08;Internet Protocol Address&#xff09;是每个连接到互联网的设备的唯一标识符。IP地址可以分为IPv4和IPv6两种类型。IPv4地址是由32位二进制数表示&#xff0c;通常分为四个八位组&am…...

dledger原理源码分析系列(一)架构,核心组件和rpc组件

简介 dledger是openmessaging的一个组件&#xff0c; raft算法实现&#xff0c;用于分布式日志&#xff0c;本系列分析dledger如何实现raft概念&#xff0c;以及dledger在rocketmq的应用 本系列使用dledger v0.40 本文分析dledger的架构&#xff0c;核心组件&#xff1b;rpc组…...

第七节:如何浅显易懂地理解Spring Boot中的依赖注入(自学Spring boot 3.x的第二天)

大家好&#xff0c;我是网创有方&#xff0c;今天我开始学习spring boot的第一天&#xff0c;一口气写了这么多。 这节通过一个非常浅显易懂的列子来讲解依赖注入。 在Spring Boot 3.x中&#xff0c;依赖注入&#xff08;Dependency Injection, DI&#xff09;是一个核心概念…...

Postman自动化测试实战:使用脚本提升测试效率

在软件开发过程中&#xff0c;接口测试是确保后端服务稳定性和可靠性的关键步骤。Postman作为一个流行的API开发工具&#xff0c;提供了强大的脚本功能来实现自动化测试。通过在Postman中使用脚本&#xff0c;测试人员可以编写测试逻辑&#xff0c;实现测试用例的自动化执行&am…...

CSMA/CA并不是“公平”的

CSMA/CA会造成过于公平,对于最需要流量的节点,是最不友好的,而对于最不需要流量的节点,则是最友好的。 CSMA/CA是优先公平来工作的。 CSMA/CA首先各节点使用DIFS界定air idle,在此期间大家都等待 其次,为了同时发送引起碰撞,在DIFS之后随机从CWmin和CWmax之间选择一个时…...

【漏洞复现】I doc view——任意文件读取

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 I doc view 在线文档预览是一个用于查看、编辑、管理文档的工具…...

图数据库 vs 向量数据库

最近大模型出来之后&#xff0c;向量数据库重新翻红&#xff0c;业界和市场上有不少声音认为向量数据库会极大的影响图数据库&#xff0c;图数据库市场会萎缩甚至消失&#xff0c;今天就从技术原理角度来讨论下图数据库和向量数据库到底差别在哪里&#xff0c;适合什么场景&…...

平台维护工作内容/周口seo推广

基本数据类型(int,bool,str) 1.基本数据数据类型: int 整数 str 字符串. 一般不存放大量的数据 bool 布尔值. 用来判断. True, False list 列表.用来存放大量数据, []表示. 里面可以装各种数据类型. tuple 元组. 只读列表. () 表示 …...

手机网站焦点图代码/百度入口网页版

HADDR HADDR是来自AHB总线上地址线&#xff0c;是字节地址。连接到FSMC_A[25:0]&#xff0c;再连接到外部的存储器&#xff0c; 地址线 首先明确一点&#xff0c;26根地址线&#xff0c;它是26个位。它的寻址空间或者寻址容量是2^26&#xff0c;单位是Byte。HADDR是字节地址…...

网站建设初衷/淘宝店铺运营推广

解决步骤&#xff1a;1、top命令查看CPU占用情况可以看到11042进程占用了非常多的CPU资源2、查看F5并发曲线&#xff1a;为什么应用耗费了这么多的线程&#xff0c;难道是用户量突然上来了&#xff0c;调取了F5的访问曲线图&#xff0c;可以看到在15:57左右并发量突然猛涨&…...

河北省建设工程招标投标网站/网络推广网站电话

前端开发前端“前端”&#xff0c;“前端”和“前端”。 您过去可能已经看过或使用了上述所有方法&#xff0c;但是哪个正确&#xff1f; 让我们来看看&#xff01; wikipedia.org paulirish.com 网站&#xff1a;http&#xff1a;//paulirish.com“前端”约154个结果&…...

温岭网站开发/朋友圈信息流广告投放价格

Exchange Server 2016 RTM 可以在 Windows Server 2012、Windows Server 2012 R2 和 Windows Server 2016 的标准版和企业版中进行部署安装&#xff0c;但 Exchange Server 2016 只支持完整 GUI 的 Windows Server 而不支持核心安装的系统&#xff0c;本文我们将对快速部署方式…...

网站建设的好处论文/seo优化师

提要光线在图形学中可以简单地用向量来表示&#xff1a;r(t) o td, o表示光线的出发点&#xff0c;d表示光线的方向&#xff0c;通常是单位向量&#xff0c;r表示光线在t时刻的位置。光线求交在图形学中有着非常重要的应用&#xff0c;比如Global Illumination,collision det…...