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

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...