2009-10-01 13:41:00 gisoracle 阅读数 947
  • C# 实战项目——快递单打印软件

    实践是检验技术的最佳标准。学编程就是用编程!本课由小科带领大家完成一个C#项目——快递单打印软件 随着电商的普及,同学们对快递都不陌生,填写快递单和管理快递记录是一项比较烦琐的工作,传统的手工填写和管理快递单的方式会使工作效率非常低,本课程带领同学们一起完成一个快递单打印软件。 亮点 精彩视频逐步讲解 程序开发实现流程讲解 附带项目源码,代码注释全 主要知识点 1、如何使用已有窗体资源  2、分割Form窗体 3、DataGridView数据表格的使用  4、使用C#操作SQL Server数据库 5、以二进制形式在数据库中存储数据  6、自定义控件的应用 7、C#打印组件的使用  8、控件的动态添加与删除

    1495 人正在学习 去看看 王小科

C# 打印大图片

C# 打印大图片有两种方式
1、缩小到纸张大小
2、自动分割,分页打印
主界面


缩小到纸张大小预览



分页打印

下载地址
http://files.cnblogs.com/gisoracle/prnbigpic.rar

2012-06-08 21:09:06 jalyflf 阅读数 371
  • C# 实战项目——快递单打印软件

    实践是检验技术的最佳标准。学编程就是用编程!本课由小科带领大家完成一个C#项目——快递单打印软件 随着电商的普及,同学们对快递都不陌生,填写快递单和管理快递记录是一项比较烦琐的工作,传统的手工填写和管理快递单的方式会使工作效率非常低,本课程带领同学们一起完成一个快递单打印软件。 亮点 精彩视频逐步讲解 程序开发实现流程讲解 附带项目源码,代码注释全 主要知识点 1、如何使用已有窗体资源  2、分割Form窗体 3、DataGridView数据表格的使用  4、使用C#操作SQL Server数据库 5、以二进制形式在数据库中存储数据  6、自定义控件的应用 7、C#打印组件的使用  8、控件的动态添加与删除

    1495 人正在学习 去看看 王小科
最近项目中需要用到打印HTML页面,需要指定区域打印,使用jquery.PrintArea.js 插件

用法:

$("div#printmain").printArea();


但还是会打印DIV后面的内容,这里可以使用CSS控制打印分页

<div style="page-break-after: always;"></div>


有时用CSS控制分页了但还是会连续打印页面,这里就可以用上PrintArea 插件中的属性参数。


PrintArea部分源码:


var modes = { iframe : "iframe", popup : "popup" };
var defaults = { mode : modes.iframe,
popHt : 800,
popWd : 800,
popX : 200,
popY : 200,
popTitle : '',
popClose : false ,
twoDiv : '', //自已扩展的属性,为满足变态需求
pageTitle: ''};//自已扩展的属性,为满足变态需求



可以看出插件中定义的属性格式为JSON,下面介绍部分属性

modes定义了两个属性,指定popup时会打开新窗口,可以视为打印预览页面,默认为iframe。

@popClose | [boolean] | (false),true 打印完成后是否开闭预览页面,默认为false(不关闭)。


$("div#printmain").printArea({mode:"popup",popClose:true});

这样就可以指定DIV打印了。

下面说一下我新增两个属性的用途
twoDiv:
需要打印的第二个DIV ,当然会是第二页,这个页面比较长,需要自动分页,并且表格中每行都不一样,有些行跨了多行,这里打印出来,一行可能会打印在两张纸上。

pageTitle:
第二个DIV分成多页里,每一页的表头都需要一样,这个参数就是公用表头。

这两个参数都对应着页面中的DIV,如:

<div id="pageTitle" style="display: none;">

页面定义好后,我们看看插件中是如何处理我们的页面的。

writeDoc.open();
writeDoc.write(html); //打找一个窗口关写窗口中的HTML代码
writeDoc.close();

printWindow.focus();
printWindow.print();


下面是生成html的代码

html+=docType() + "<html>" + getHead() + getBody(thisPage) + "</html>";

插件中都定义了相义的方法,我没有做任何修改,这里我就不粘贴了。


下面是我的思路:
需在将一个DIV中的内容分成多页,且一行不跨多页,我们就得在生成html 代码上下功夫了。

首先找出DIV中的所有行,当公共表头加上这些行后高度达到一页,就需要分页了,这里就有可以一页中最后一行刚好跨了多页,将这一行保存下来,放到下一页。

每一页生成完成后都需要在HTML标签后面加上CSS分页标记,这样就打印机就会乖乖的分页。

说明一下,生成的预览页面一页就是一个HTML页面,它有对应的表头与DTD信息。

有人可能明明预览只有4页,而打印出来总会多一页,这时你需要检验一下你生成的页面中分页标记是不是在HTML标签之前。
分面标记一定要在HTML标签之后,这样可解决打印多打一页问题。

PS:
下面我会传上我修改过后的JS插件,由于我项目周期的原因,代码中很多部分都是写死了,只是为了解决本次打印的问题。所在代码中写得很乱,希望大家将究着看

同事也希望哪位能够再优化一下,使之通用。

第一篇博客,大家将就着看。
2017-03-17 10:44:15 lcj401175209 阅读数 1503
  • C# 实战项目——快递单打印软件

    实践是检验技术的最佳标准。学编程就是用编程!本课由小科带领大家完成一个C#项目——快递单打印软件 随着电商的普及,同学们对快递都不陌生,填写快递单和管理快递记录是一项比较烦琐的工作,传统的手工填写和管理快递单的方式会使工作效率非常低,本课程带领同学们一起完成一个快递单打印软件。 亮点 精彩视频逐步讲解 程序开发实现流程讲解 附带项目源码,代码注释全 主要知识点 1、如何使用已有窗体资源  2、分割Form窗体 3、DataGridView数据表格的使用  4、使用C#操作SQL Server数据库 5、以二进制形式在数据库中存储数据  6、自定义控件的应用 7、C#打印组件的使用  8、控件的动态添加与删除

    1495 人正在学习 去看看 王小科

最近在做某药厂的管理系统,包括进销存以及生产管理,其中需要打印单据,开始使用aspose.cell实现打印功能,运行不错,这个第三方表格操作非常简单便捷。但是突然有一天客户反应单子打印异常,发给我图片一看才知道原因。一开始设计的时候设置了页面的模板的高度,一般情况下能够满足客户需求,但是当物品种类达到固定数值后,软件就自动分页了,导致单子中间出现了很大一片空白,影响美观。

于是乎博主开启了疯狂的修BUG阶段,可能水平有限,对于套打的打印方式,高度我不会设置,因为模板一般高度固定(求大神指点)。经过一番激烈的思想斗争过后,博主放弃了aspose。cell,的方案,重新捡起自带的printdocument控件,这个控件真的很简单,操作也很方便,但是唯一不足就是打印内容需要自己定义,于是我又开始了表格的设计,计算各种宽高。

最后的还是被博主解决了,通过这个事情,我想和大家分享的是:

        别人的东西再好,不适合自己也不能盲目从众,结果只能自己挖的坑自己填。

废话太多,上源码。点击打开链接下载工程源码


2019-12-26 12:16:16 qq_42027345 阅读数 22
  • C# 实战项目——快递单打印软件

    实践是检验技术的最佳标准。学编程就是用编程!本课由小科带领大家完成一个C#项目——快递单打印软件 随着电商的普及,同学们对快递都不陌生,填写快递单和管理快递记录是一项比较烦琐的工作,传统的手工填写和管理快递单的方式会使工作效率非常低,本课程带领同学们一起完成一个快递单打印软件。 亮点 精彩视频逐步讲解 程序开发实现流程讲解 附带项目源码,代码注释全 主要知识点 1、如何使用已有窗体资源  2、分割Form窗体 3、DataGridView数据表格的使用  4、使用C#操作SQL Server数据库 5、以二进制形式在数据库中存储数据  6、自定义控件的应用 7、C#打印组件的使用  8、控件的动态添加与删除

    1495 人正在学习 去看看 王小科

目录

代码展示:

1、将勾选的数据以json数组的形式传到后台

2、后端代码(java、C#)

3、最后一步就是拿着后台传过来的图片码取打印喽


最近在项目中遇到在前端页面勾选数条数据一键批量打印二维码标签的需求,一开始也是非常的头疼,经过好几天的百度以及思考得出以下方案:

1、将勾选的数据以json数组的形式传到后台,并在当前页面插入隐藏的iframe标签

2、后端循环将单个数据传入打印模板页面,使用Selenium在不打开浏览器的情况下渲染页面,并且在页面中使用html2canvas将要打印的部分(可以用一个div包起来,我这里模板是一个table)转为图片(base64码)

3、将后端穿过来的多个图片码传入动态生成的多个img标签并写入页面隐藏的iframe标签中,之后调用浏览器的打印就OK了。

代码展示:

1、将勾选的数据以json数组的形式传到后台

页面使用的是easyUI, json数据差不多是这样的(你可以根据你的后端程序自己来设置)

[{'code':'111','title1':'998','title2':'芜湖南方','filedname':'名字*状态*手机号','filedval':'zzz*活跃*123456'},
{'code':'222','title1':'1001','title2':'芜湖南方','filedname':'名字*状态*手机号','filedval':'zzz*活跃*123456'},
{'code':'333','title1':'975','title2':'芜湖南方','filedname':'名字*状态*手机号','filedval':'zzz*活跃*123456'}]

在当前页面添加隐藏iframe标签,后面打印就靠这个(src的页面相当于做好样式的空页面)

//添加iframe标签
    var body = document.getElementsByTagName("body");
    var div = document.createElement("div");
    div.innerHTML = '<iframe src="http://10.1.6.243:8976/Common/print.html" id="iframeprint" style="display: none;"></iframe>';
    document.body.appendChild(div);

2、后端代码(java、C#)

需下载chromdriver.exe,地址如下:

http://npm.taobao.org/mirrors/chromedriver/?tdsourcetag=s_pcqq_aiomsg

谷歌浏览器(官网下载):

https://www.google.cn/chrome/

2.1 java 

以下是我引得各种包(有的可能不需要)解析json用的是阿里的fastjson

<dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-api -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-api</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-chrome-driver -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-support -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-support</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-server</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-remote-driver -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-remote-driver</artifactId>
            <version>3.2.0</version>
        </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

 java控制器:

@ResponseBody
    @PostMapping("/get")
    public String getImgSrcs(@RequestBody String pars){
        System.out.println(pars);
        return imgService.getImgUrls(pars);
    }

service方法:

@Override
    public String getImgUrls(String jsonPars){
        // 存储返回的base64图片编码
        JSONObject imageBase64List = new JSONObject();
        // 将参数转为json数组
        JSONArray jsonArray = JSONObject.parseArray(jsonPars);
        try {
            // 加载驱动,Chromedriver.exe的地址
            System.setProperty("webdriver.chrome.driver", "D:\\phantomjs-2.1.1-windows\\chromedriver.exe");
            ChromeOptions options = new ChromeOptions();
            // 不打开浏览器访问页面
            options.addArguments("--headless");
            options.addArguments("--disable-gpu");
            WebDriver driver = new ChromeDriver(options);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObj = jsonArray.getJSONObject(i);
                String code = jsonObj.getString("code");
                String title1 = jsonObj.getString("title1");
                String title2 = jsonObj.getString("title2");
                String filedname = jsonObj.getString("filedname");
                String filedval = jsonObj.getString("filedval");
                // 让浏览器访问空间主页
                String url = "http://localhost:63342/springboot2.X/DataBase/templates/qrcode.html?code="+code+"&title1="+title1+"&title2="+title2+"&filedname="+filedname+"&filedval="+filedval;
                driver.get(url);
                //加入一段休眠时间,防止js脚本执行没完成
                Thread.sleep(1000);
                String imgSrc = driver.findElement(By.id("sss")).getAttribute("value");
                imageBase64List.put(Integer.toString(i), imgSrc);
            }
            driver.quit();
            return imageBase64List.toJSONString();
        }catch (Exception e){
            return e.getMessage();
        }

    }

因为前端的html2canvas方法是异步的,后台不好直接获取这个function的结果,因此我将它的结果写在一个id为sss的input框里了,代页面js脚本执行完成直接

String imgSrc = driver.findElement(By.id("sss")).getAttribute("value");

就可以拿到转好的base64码

以下是我的模板页面qrcode.html(js生成二维码用到了jquery.qrcode.min.js,基本使用页面中就有)

 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<script src="js/jquery-3.1.0.min.js"></script>
		<script src="js/jQuery.print.js"></script>
		<script src="js/html2canvas.js"></script>
		<script src="js/jquery.qrcode.min.js"></script>
	</head>
	<body>
		<table id="print_area" cellpadding="0" cellspacing="0" align="center" style="width:420px">
		    <tbody id="tbody">
		        <tr class="firstRow">
		            <td width="200 px" valign="center" rowspan="2" colspan="1" style="word-break: break-all;">
		                <p style="text-align:center">
		                    <img src="img/logo.png" title="logo.png" alt="logo.png" style="width: 270px; height: 41px;"/>
		                </p>
		            </td>
		            <td width="220 px" valign="center">
		                <input type="text" id="title1" value="" style="text-align: center;font-size: 21px;border: none;width: 200px;"/>
		            </td>
		        </tr>
		        <tr>
		            <td valign="top">
		                <input type="text" id="title2" value="" style="text-align: center;font-size: 21px;border: none;width: 200px;"/>
		            </td>
		        </tr>
		        <tr>
		            <td align="left"></td>
		            <td align="center" rowspan="1" colspan="1">
		                <div id="qr_container" style="margin:auto; position:relative; text-align: center;"></div>
		            </td>
		        </tr>
		    </tbody>
		</table>
		<input id="sss" type="text" value="123" style="display: none"/>
	</body>
    <script>
        // 获取参数
        function getUrlParam(key) {
            var url = window.location.search;
            var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
            var result = url.substr(1).match(reg);
            return result ? decodeURIComponent(result[2]) : null;
        }

        $(function () {
            // 生成二维码
            var codeval = getUrlParam("code");
            $('#qr_container').qrcode({render: "canvas", height: 170, width: 170, correctLevel: 0, text: codeval});

            // 反填title
            $("input[id='title1']").val(getUrlParam('title1'));
            $("input[id='title2']").val(getUrlParam('title2'));

            // 根据传过来的字段信息增加或减少行数
            var filedname = getUrlParam("filedname");
            var filedval = getUrlParam("filedval");
            var names = filedname.split('*');
            var vals = filedval.split('*');
            for (var i = 0; i < names.length; i++) {
                if (i == 0) {
                    // 与二维码在同一行的单元格
                    var code_td = $("#qr_container").closest("tr").find("td").eq(0);
                    code_td.html(inputHtml(names[i], vals[i]));
                    continue;
                }
                var code_td = $("#qr_container").closest("td");
                var editTable = document.getElementById("tbody");
                var tr = document.createElement("tr");
                var td = document.createElement("td");
                td.setAttribute("align", "left");
                td.innerHTML = inputHtml(names[i], vals[i]);
                tr.appendChild(td);
                editTable.appendChild(tr);
                code_td.attr("rowspan", i + 1);
            }
            html2img();
        });

        // 将table转为img
        function html2img(){
            //创建一个新的canvas
            var _canvas = document.getElementById("print_area");
            var w = parseInt(window.getComputedStyle(_canvas).width);
            var h = parseInt(window.getComputedStyle(_canvas).height);
            var opts = {
                dpi: window.devicePixelRatio*10,
                scale: 4,
                width: w, //dom 原始宽度
                height: h,
                allowTaint: true,
                useCORS: true
            };
            html2canvas(_canvas, opts).then(function (canvas){
                var MIME_TYPE = "image/png";
                var imgURL = canvas.toDataURL(MIME_TYPE, 1.0);
                $('#sss').val(imgURL);
            })
        }

        // 动态拼接input
        function inputHtml(name, value){
            return "<input type='text' value='"+name+"' align='center' style='width:90px;text-align: right;font-size: 27px;border: none;font-weight:bold'/><label style='font-size:20px;font-weight:bold;'>:</label><input type='text' value='"+value+"' align='center' style='width:90px;font-size: 27px;border: none;font-weight:bold'/>";
        }
    </script>
</html>

以下是C#代码(跟java差不多)

需要引两个包

 代码如下:

public class ImgService
    {
        public String html2img(String pars)
        {
            JObject imageBase64List = new JObject();
            // 转为json数组
            JArray arr = (JArray)JsonConvert.DeserializeObject(pars);
            // 设置chromedriver.exe所在的目录(不是详细地址,是上一层目录)
            String exePath = "D:\\phantomjs-2.1.1-windows";
            ChromeOptions options = new ChromeOptions();
            // 谷歌浏览器chrome.exe的地址
            options.BinaryLocation = "C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe";
            options.AddArguments("--headless");
            options.AddArguments("--disable-gpu");
            using (IWebDriver driver = new ChromeDriver(exePath, options))
            {
                for (int i = 0; i < arr.Count; i++)
                {
                    JObject obj = (JObject)arr[i];
                    var code = obj["code"];
                    var title1 = obj["title1"];
                    var title2 = obj["title2"];
                    var filedname = obj["filedname"];
                    var filedval = obj["filedval"];
                    // 让浏览器访问空间主页
                    String url = "http://10.1.6.243:8976/Common/qrcode.html?code=" + code + "&title1=" + title1 + "&title2=" + title2 + "&filedname=" + filedname + "&filedval=" + filedval;
                    driver.Navigate().GoToUrl(url);
                    //加入一段休眠时间,防止js脚本执行没完成
                    Thread.Sleep(500);
                    String imgSrc = driver.FindElement(By.Id("sss")).GetAttribute("value");
                    imageBase64List.Add(i.ToString(), imgSrc);
                }
                driver.Quit();
            }
            return JsonConvert.SerializeObject(imageBase64List);
        }
    }

3、最后一步就是拿着后台传过来的图片码取打印喽

$.ajax({
					type: "post",
					async: false,
					//contentType: "text/plain",  // java接口要加,否则解析json出错
					url: "http://10.1.6.243:211/ImgSrcHandler.ashx",
					dataType: "json",
					data: {"pars":JSON.stringify(pars)},
					success: function (data)
					{
					   var html = "";
					   for(var key in data){
						   console.log(data[key]);
                           // 一定要加page-break-after: always;这样才能分页
						   html += "<div align='center'><img class='container' src='"+data[key]+"' style='page-break-after: always;'/></div>";
					   }
					   //console.log(html);
					   var iframewin = document.getElementById('iframeprint');				   
                       iframewin.contentWindow.postMessage(html,'*'); 
					   setTimeout(function(){iframewin.contentWindow.print()}, 500);
					   //iframewin.contentWindow.location.reload();
					},
					error: function (XMLHttpRequest, textStatus, errorThrown) {}
				});

注意这里你当前页面所在的域名端口应和iframe所连接的页面是一致的(放在一个项目下就行),否则会引起跨域的问题

 我的print.html如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="js/jquery-3.1.0.min.js"></script>
		<script src="js/jquery.qrcode.min.js"></script>
		<script src="js/jQuery.print.js"></script>
		<style type="text/css" media="print">
			.noprint{
				display: none;
				}
			@page{
				margin:auto 0mm;
				//控制是使用a4还是使用其它纸张规格,我这里是80*50的纸
				size:auto 80mm 50mm;
			}
			.container{
				display: block;
				width: 80mm;
				height: auto;  
				max-width: 100%;  
				max-height: 100%;  
			}
		</style>
	</head>
	<body>
	</body>
	<script>
		addEventListener('message', e => {
		    // e.data为父页面发送的数据
		    document.body.innerHTML = e.data;
		})
	</script>
</html>

最后,结果如下:

我的方案就是这样的,但是遇到一会打十几个标签那就得很慢了(十多秒),如果您有更好的方案欢迎留言讨论 

2015-07-29 12:22:56 hongzhongyang1223 阅读数 0
  • C# 实战项目——快递单打印软件

    实践是检验技术的最佳标准。学编程就是用编程!本课由小科带领大家完成一个C#项目——快递单打印软件 随着电商的普及,同学们对快递都不陌生,填写快递单和管理快递记录是一项比较烦琐的工作,传统的手工填写和管理快递单的方式会使工作效率非常低,本课程带领同学们一起完成一个快递单打印软件。 亮点 精彩视频逐步讲解 程序开发实现流程讲解 附带项目源码,代码注释全 主要知识点 1、如何使用已有窗体资源  2、分割Form窗体 3、DataGridView数据表格的使用  4、使用C#操作SQL Server数据库 5、以二进制形式在数据库中存储数据  6、自定义控件的应用 7、C#打印组件的使用  8、控件的动态添加与删除

    1495 人正在学习 去看看 王小科
循环等打印异常。解决方法如下
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>WEB打印控件LODOP的样例八:打印网页图片</title>
<script language="javascript" src="LodopFuncs.js"></script>
</head>
<body>

<p>3:按原图比例(不变形)缩放打印模式,看看<a href="javascript:myPreview3();">打印预览3</a>。</p>

<script language="javascript" type="text/javascript">
var LODOP; //声明为全局变量
var count=0;
function myPreview3() {
LODOP=getLodop();
//LODOP.PRINT_INIT("打印控件功能演示_Lodop功能_打印图片3");
LODOP.SET_PRINT_PAGESIZE(1,580,500,0);
LODOP.ADD_PRINT_TEXT(10,70,100,40,"溯源码");
LODOP.ADD_PRINT_BARCODE(22,48,128,106,"QRCode","65020100007001000060");
LODOP.ADD_PRINT_TEXT(110,24,325,40,"65020100007001000060")
LODOP.SET_PRINT_STYLEA(0,"FontSize",10);
LODOP.SET_PRINT_STYLEA(0,"Stretch",2);//按原图比例(不变形)缩放模式
LODOP.PRINT();
count=count+1;
if(count<2){
sleep(1000);
myPreview3();
}else{
count=0;
return;
}

};
function sleep(numberMillis) {
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true) {
now = new Date();
if (now.getTime() > exitTime)
return;
}
}
</script>

</body>
</html>

win32中使用打印机

阅读数 1123

没有更多推荐了,返回首页