前提准备:
1. 项目中至少需要引入的jar包,注意版本:
a) core-renderer.jar
b) freemarker-2.3.16.jar
c) iText-2.0.8.jar
d) iTextAsian.jar
上代码:
注释: 此类为自定义的Tag类的基类,在action中怎么放的数据,在ftl中就怎么取数据,简洁明了。
1. 自定义Tag类的基类
/** * 通用的生成pdf预览和生成打印的html文件 * * @author xg君 * */ public abstract class PDFTag extends BodyTagSupport { private static final long serialVersionUID = 1L; // 标签属性变量 private String json = ""; private String tempDir = ""; // 非标签属性变量 private Map<String, Object> rootMap = new HashMap<String, Object>(); private String templateStr = null; private String freemarkereConfigurationBeanName = null; private String fileName = null; private String basePath = null; private String fileEncoding = "utf-8"; @Override public int doStartTag() throws JspException { setConfigParams(); WebApplicationContext application = WebApplicationContextUtils.getWebApplicationContext(pageContext .getServletContext()); doServiceStart(); String ctx = (String) pageContext.getAttribute("ctx"); rootMap.put("ctx", ctx); Map<String, Object> map = parseJSON2Map(json); rootMap.putAll(map); if (freemarkereConfigurationBeanName == null) { try { throw new CstuException("FreemarkereConfigurationBeanName不能为空!"); } catch (CstuException e) { e.printStackTrace(); } } Configuration cptFreemarkereConfiguration = (Configuration) application .getBean(freemarkereConfigurationBeanName); try { if (templateStr == null) { throw new CstuException("模板文件不能为空!"); } Template template = cptFreemarkereConfiguration.getTemplate(templateStr); if (basePath == null) { throw new CstuException("文件的基本路径(父路径)不能为空!"); } File htmlPath = new File(tempDir + File.separator + basePath); if (!htmlPath.exists()) { htmlPath.mkdirs(); } if (fileName == null) { throw new CstuException("生成的html文件名不能为空!"); } File htmlFile = new File(htmlPath, File.separator + fileName); if (!htmlFile.exists()) { htmlFile.createNewFile(); } BufferedWriter out = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(htmlFile), fileEncoding)); template.process(rootMap, out); out.flush(); doServiceDoing(); // 显示在页面 template.process(rootMap, pageContext.getResponse().getWriter()); } catch (Exception e) { e.printStackTrace(); } doServiceEnd(); return SKIP_BODY; } /** * 配置基础参数,如 */ public abstract void setConfigParams(); /** * 业务处理方法-开始 填充数据 * * @return */ public abstract void doServiceStart(); /** * 业务处理方法-执行中 备用,可空实现,若rootMap中存在双份数据则可在此处填充判断条件 * * @return */ public abstract void doServiceDoing(); /** * 业务处理方法-结束 清空rootMap并调用垃圾回收,也可空实现 * * @return */ public abstract void doServiceEnd(); /** * 将元素放入rootMap中 */ public void putKV(String key, Object value) { rootMap.put(key, value); } /** * 将map放入rootMap中 * * @param m */ public void putMap(Map m) { rootMap.putAll(m); } public void clear() { rootMap.clear(); rootMap = null; } /** * 移除元素 * * @param key * @return */ public Object remove(String key) { return rootMap.remove(key); } public static Map<String, Object> parseJSON2Map(String jsonStr) { Map<String, Object> map = new HashMap<String, Object>(); JSONObject json = JSONObject.fromObject(jsonStr); for (Object k : json.keySet()) { Object v = json.get(k); if (v instanceof JSONArray) { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Iterator<JSONObject> it = ((JSONArray) v).iterator(); while (it.hasNext()) { JSONObject json2 = it.next(); list.add(parseJSON2Map(json2.toString())); } map.put(k.toString(), list); } else { map.put(k.toString(), v); } } return map; } public String getJson() { return json; } public void setJson(String json) { this.json = json; } public String getTempDir() { return tempDir; } public void setTempDir(String tempDir) { this.tempDir = tempDir; } public String getTemplateStr() { return templateStr; } public void setTemplateStr(String templateStr) { this.templateStr = templateStr; } public String getFreemarkereConfigurationBeanName() { return freemarkereConfigurationBeanName; } public void setFreemarkereConfigurationBeanName(String freemarkereConfigurationBeanName) { this.freemarkereConfigurationBeanName = freemarkereConfigurationBeanName; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getBasePath() { return basePath; } public void setBasePath(String basePath) { this.basePath = basePath; } public String getFileEncoding() { return fileEncoding; } public void setFileEncoding(String fileEncoding) { this.fileEncoding = fileEncoding; } }
注释: setConfigParams方法是用于调用接口定义的配置参数的方法,如:templateStr,basePath等,doServiceStart,doServiceDoing和doServiceEnd等方法用于处理业务逻辑,比如我的需求是做出合同在一个页面显示,要分页,要加水印,但生成的pdf样式与预览的是不同的,所以我加了一个doServiceDoing中给rootMap添加判断条件,这样就能一个flt文件作出两种效果(预览和打印),当然如果预览和打印要一样的效果,doServiceDoing方法可以空实现。这四个方法总结一下就是:
1. setConfigParams : 配置参数
2. doServiceStart : 填充数据/条件
3. doServiceDoing : 填充数据/条件,到这里是个分界线,此方法之前,rootMap数据先进入html再进入浏览器(预览),此方法之后,rootMap数据会再次进入html文件,结束,所以此处可写判断
4. doServiceEnd : 可有可无,我还是写上了,万一哪天的数据集太大,此处便可以在数据填充完后,清理掉,节省内存空间
2. PDFTag的子类
/** * 用户自定义PDFTag类 * * @author xg君 * */ public class ViewPDFTag extends PDFTag { private static final long serialVersionUID = 4528567203497016087L; private String prjNature = ""; private String bookName = ""; private String prjCode = ""; /** * 用户自定义的配置参数 */ public PDFConfigurationInterface pDFConfigurationInterface = new PDFConfigurationInterface() { @Override public void configTemplateStr() { // 横,纵向 if (prjNature.equalsIgnoreCase("2") || prjNature.equalsIgnoreCase("1")) { setTemplateStr("wj-project-print.ftl"); } } @Override public void configFreemarkereConfigurationBeanName() { setFreemarkereConfigurationBeanName("cptFreemarkereConfiguration"); } @Override public void configFileName() { // 填入html文件 setFileName(prjCode + ".html"); } @Override public void configFileEncoding() { // 默认utf-8 } @Override public void configBasePath() { setBasePath("html_pdf"); } }; @Override public void doServiceStart() { putKV("prjNature", prjNature); putKV("bookName", bookName); putKV("flag", "0"); } @Override public void doServiceDoing() { putKV("flag", "1"); } @Override public void doServiceEnd() { clear(); System.gc(); } public String getPrjNature() { return prjNature; } public void setPrjNature(String prjNature) { this.prjNature = prjNature; } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getPrjCode() { return prjCode; } public void setPrjCode(String prjCode) { this.prjCode = prjCode; } @Override public void setConfigParams() { pDFConfigurationInterface.configTemplateStr(); pDFConfigurationInterface.configFreemarkereConfigurationBeanName(); pDFConfigurationInterface.configFileName(); pDFConfigurationInterface.configBasePath(); pDFConfigurationInterface.configFileEncoding(); } }
注释: PDFConfigurationInterface 是自定义的标签参数配置接口,子类必须定义一个该接口的实现类的成员变量或定义一个成员变量内部类,并在setConfigParams方法中调用使其生效。
子类的成员变量接收在tld文件中配置的属性。
3. 自定义的标签参数配置接口
/** * PdfTag类的配置 * * @author xg君 * */ public interface PDFConfigurationInterface { /** * 设置模板名称 */ void configTemplateStr(); /** * 设置配置的FreemarkereConfigurationBean的名称 */ void configFreemarkereConfigurationBeanName(); /** * 设置生成的html文件名称 */ void configFileName(); /** * 设置生成的html文件的基本路径(父目录) */ void configBasePath(); /** * 设置文件编码,默认utf-8 */ void configFileEncoding(); }
4. 自定义异常类
/** * 自定义异常类 * * @author Administrator * */ public class CstuException extends Exception { private static final long serialVersionUID = 4266461814747405870L; public CstuException(String msg) { super(msg); } }
5. tld文件配置
<tag> <name>print</name> <tagclass>com.iris.taglib.web.PreviewPDFTag</tagclass> <bodycontent>JSP</bodycontent> <attribute> <name>json</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>prjNature</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>bookName</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>tempDir</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>prjCode</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
6. action
/** * 处理PDF导出 * */ @Namespace("/export") @Results({ @Result(name = "exceltemplate", location = "/WEB-INF/content/pdf/export-pdf.jsp"), @Result(name = "exprotPdf2", location = "/WEB-INF/content/project/project/export/export-pdf2.jsp") }) public class ExportPdfAction extends ActionSupport { private static final long serialVersionUID = -5454188364706173477L; @Value("${tempDir}") private String tempDir; @Value("${pdfFont}") private String pdfFont; @Value("${staticResRootDir}") private String staticResRootDir; @Value("${staticResRootDir2}") private String staticResRootDir2; @Value("${WaterMarkImgDir}") private String waterMarkImgDir; @Autowired private ProjectService projectService; @Autowired private PersonService personService; @Autowired private ConstDictionaryService constDictionaryService; @Autowired private FdPlanDetailService fdPlanDetailService; @Autowired private ServiceFactory serviceFactory; @Action("exprotPdf2") public String exprotPdf2() { String prjCode = Struts2Utils.getParameter("prjCode"); prjCode = Struts2Utils.decodeDesString(prjCode); Project project = projectService.getProjectById(Long.parseLong(prjCode)); Map<String, String> baseInfo = new HashMap<String, String>(); baseInfo.put("tempDir", tempDir); // 项目编号 baseInfo.put("prjCode", prjCode); // 项目类型 String prjNature = project.getPrjNature(); baseInfo.put("prjNature", prjNature); // 水印名称格式:watermark+"-"+prjNature baseInfo.put("waterMarkImg", waterMarkImgDir + File.separator + "watermark-" + prjNature + ".png"); // 负责人 Person person = personService.getPerson(project.getPsnCode()); String zhName = person.getZhName(); baseInfo.put("zhName", addStr(9, "<br/>", zhName)); // 项目编号 String prjNo = project.getPrjNo(); baseInfo.put("prjNo", prjNo); // 项目来源 ConstDictionary cd = constDictionaryService.findCdByCategoryCode("project_from", project.getGrantNo()); String project_from = cd.getzh_cn_caption(); baseInfo.put("project_from", addStr(9, "<br/>", project_from)); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 起止年限 String startDate = sdf.format(project.getStartDate()); String endDate = sdf.format(project.getEndDate()); String startEndDate = startDate + "~" + endDate; baseInfo.put("startEndDate", startEndDate); // 项目类别--资助类别 String grantName = project.getGrantName(); baseInfo.put("grantName", addStr(9, "<br/>", grantName)); // 合同金额 String totalAmt = project.getTotalAmt().toString(); BigDecimal totalAmt_ = checkNumber(totalAmt); baseInfo.put("totalAmt", totalAmt_.toString()); // 项目名称 String zhTitle = project.getZhTitle(); baseInfo.put("zhTitle", addStr(38, "<br/>", zhTitle)); List<Map<String, String>> ps = null; try { ps = getMembers(project.getPrjXml()); } catch (Exception e) { e.printStackTrace(); } String bookName = ""; // 判断项目类型 Map<String, Object> itemMap = new HashMap<String, Object>(); if (prjNature.equalsIgnoreCase("1")) { bookName = "第一份合同"; // 获取fdPlanDetail List<Map<String, Object>> list = fdPlanDetailService.getFdPlanDetailsByPrjCode(Long.parseLong(prjCode)); // test /* * Map<String, Object> test = new HashMap<String, Object>(); test.put("itemValue", "6"); * test.put("itemName", "差旅费"); test.put("remark", "xxxxx"); list.add(test); */ for (Map<String, Object> m : list) { String key = (String) m.get("ITEMNAME"); BigDecimal itemValue = (BigDecimal) m.get("ITEMVALUE"); BigDecimal proportion = new BigDecimal(0.00); if (itemValue != null && totalAmt_.compareTo(new BigDecimal("0.00")) != 0) { proportion = itemValue.divide(totalAmt_, 6, BigDecimal.ROUND_HALF_EVEN); } if (itemValue == null) { itemValue = new BigDecimal("0.00"); } proportion = checkNumber(proportion.toString()); Map<String, Object> data = new HashMap<String, Object>(); // 添加比例 data.put("proportion", proportion.toString()); // 检测金额规范 BigDecimal amt = checkNumber(itemValue.toString()); data.put("itemValue", amt.toString()); // remark String remark = (String) m.get("REAMRK"); data.put("remark", remark == null ? "" : remark); itemMap.put(key, data); } } else if (prjNature.equalsIgnoreCase("2")) { bookName = "第二份合同"; } Map<String, Object> map = new HashMap<String, Object>(); map.put("baseInfo", baseInfo); map.put("projectMember", ps); map.put("itemMap", itemMap); map.put("psCount", ps.size()); map.put("psSum", 25 - ps.size()); String json = JSONObject.fromObject(map).toString(); Struts2Utils.getRequest().setAttribute("jsonData", json); Struts2Utils.getRequest().setAttribute("prjNature", prjNature); Struts2Utils.getRequest().setAttribute("bookName", bookName); Struts2Utils.getRequest().setAttribute("tempDir", tempDir); Struts2Utils.getRequest().setAttribute("prjCode", prjCode); return "exprotPdf2"; } public List<Map<String, String>> getMembers(String xmlData) throws Exception { List<Map<String, String>> list = new ArrayList<Map<String, String>>(); Document doc = DocumentHelper.parseText(xmlData); Node ps = doc.selectSingleNode("/data/project/persons"); List<Node> psList = ps.selectNodes("person"); String totalAmt = doc.selectSingleNode("/data/project/basic_info/total_amt").getText(); for (Node person : psList) { Map<String, String> map = new HashMap<String, String>(); Node fund_proportion = person.selectSingleNode("fund_proportion"); String fund_proportion_text = ""; if (fund_proportion == null) { map.put("proportion", "0.00"); map.put("fpAmt", "0.00"); } else { fund_proportion_text = fund_proportion.getText(); BigDecimal fp = new BigDecimal(fund_proportion_text); fp = fp.multiply(new BigDecimal("0.01")); fp = checkNumber(fp.toString()); map.put("proportion", fp.toString()); BigDecimal fdAmt_ = fp.multiply(new BigDecimal(totalAmt)); fdAmt_ = checkNumber(fdAmt_.toString()); map.put("fpAmt", fdAmt_.toString()); } Node psn_name = person.selectSingleNode("psn_name"); String psn_name_text = psn_name.getText(); map.put("zhName_p", addStr(9, "<br/>", psn_name_text)); Node psn_work = person.selectSingleNode("psn_work"); String psn_work_text = ""; if (psn_work != null) { psn_work_text = psn_work.getText(); } map.put("work", addStr(9, "<br/>", psn_work_text)); Node dept_code_name = person.selectSingleNode("dept_code_name"); String dept_code_name_text = ""; if (dept_code_name != null) { dept_code_name_text = dept_code_name.getText(); } map.put("deptName", addStr(9, "<br/>", dept_code_name_text)); Node psn_type_name = person.selectSingleNode("psn_type_name"); String psn_type_name_text = ""; if (psn_type_name != null) { psn_type_name_text = psn_type_name.getText(); } map.put("psnTypeName", psn_type_name_text); list.add(map); } return list; } /** * 为字符串添加指定字符 * * @param num * @param splitStr * @param str * @return */ public String addStr(int num, String splitStr, String str) { StringBuffer sb = new StringBuffer(); String temp = str; int len = str.length(); while (len > 0) { if (len < num) { num = len; } sb.append(temp.substring(0, num)).append(splitStr); temp = temp.substring(num); len = temp.length(); } return sb.toString(); } /** * 两个数字/英文 * * @param str * @param num * @return 最终索引 */ public static int getEndIndex(String str, double num) { int idx = 0; int count = 0; double val = 0.00; // 判断是否是英文/数字 for (int i = 0; i < str.length(); i++) { if ((str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') || (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') || Character.isDigit(str.charAt(i))) { val += 0.50; } else { val += 1.00; } count = i + 1; if (val >= num) { idx = i; break; } } if (idx == 0) { idx = count; } return idx; } /** * 下载pdf文件 * * @return */ @Action("downLoad") public String downLoad() { String prjCode = Struts2Utils.getParameter("prjCode"); String basePath = "html_pdf"; Project project = projectService.getProjectById(Long.parseLong(prjCode)); String zhTitle = project.getZhTitle(); FileOutputStream fos = null; // html File htmlFile = new File(tempDir + File.separator + basePath + File.separator + prjCode + ".html"); String pdfPath = tempDir + File.separator + basePath + File.separator + zhTitle + ".pdf"; try { fos = new FileOutputStream(pdfPath); String url = htmlFile.toURI().toURL().toString(); ITextRenderer renderer = new ITextRenderer(); renderer.setDocument(url); ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont(pdfFont + File.separator + "SimSun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); renderer.layout(); renderer.createPDF(fos); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fos != null) { fos.close(); } } catch (IOException e) { e.printStackTrace(); } } // 添加水印 String wartermark = ""; if (project.getPrjNature().equalsIgnoreCase("1")) { // 横向 wartermark = "CTGU横向科研项目立项通知书"; } else if (project.getPrjNature().equalsIgnoreCase("2")) { // 纵向 wartermark = "CTGU纵向科研项目立项通知书"; } String wm_pdf = tempDir + File.separator + "wm_" + project.getZhTitle() + ".pdf"; try { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(wm_pdf)); waterMark(bos, pdfPath, wartermark, staticResRootDir2 + File.separator + waterMarkImgDir + File.separator + "watermark-" + project.getPrjNature() + ".png"); } catch (Exception e2) { e2.printStackTrace(); } // 拿到pdf File pdfFile = new File(wm_pdf); BufferedOutputStream out = null; FileInputStream in = null; try { in = new FileInputStream(pdfFile); HttpServletResponse response = Struts2Utils.getResponse(); response.reset(); String fileName = zhTitle + ".pdf"; String fileName2 = URLEncoder.encode(fileName, "UTF-8"); String agent = Struts2Utils.getRequest().getHeader("USER-AGENT"); // IE if (null != agent && -1 != agent.indexOf("MSIE")) { fileName2 = new String(fileName.getBytes("GBK"), "ISO8859-1"); } else if (null != agent && -1 != agent.indexOf("Mozilla")) { fileName2 = new String(fileName.getBytes("UTF-8"), "ISO8859-1"); } response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName2 + "\""); response.setContentType(FileContentTypes.getContentType(zhTitle + ".pdf")); out = new BufferedOutputStream(response.getOutputStream()); byte[] buffer = new byte[16 * 1024]; int len = 0; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e1) { e1.printStackTrace(); } try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } // 清理残留文件 // if (htmlFile.exists()) { // htmlFile.delete(); // } File temp_file = new File(pdfPath); if (temp_file.exists()) { temp_file.delete(); } if (pdfFile.exists()) { pdfFile.delete(); } return null; } public BigDecimal checkNumber(String number) { // 初始化为6位小数 DecimalFormat df = new DecimalFormat("0.000000"); String num = df.format(Double.parseDouble(number)); BigDecimal bd = new BigDecimal(num); String val = bd.toString(); val = val.replaceAll("^(0+)", ""); val = val.replaceAll("(0+)$", ""); int idx = val.indexOf("."); int len = val.substring(idx + 1).length(); if (len < 2) { if (len == 0 && idx == 0) { bd = new BigDecimal("0.00"); } else { bd = new BigDecimal(val).setScale(2); } } else { bd = new BigDecimal(val).setScale(len); } return bd; } private String replaceStr(String str, String reVal) { Pattern pattern = Pattern.compile("^" + reVal + "+|" + reVal + "+$"); Matcher matcher = pattern.matcher(str); return matcher.replaceAll(""); } /** * 添加水印 */ private void waterMark(BufferedOutputStream bos, String input, String waterMarkName, String imagePath) { try { PdfReader reader = new PdfReader(input); PdfStamper stamper = new PdfStamper(reader, bos); int total = reader.getNumberOfPages() + 1; PdfContentByte content; BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED); PdfGState gs = new PdfGState(); for (int i = 1; i < total; i++) { content = stamper.getOverContent(i);// 在内容上方加水印 content.setGState(gs); content.beginText(); Image image = Image.getInstance(imagePath); image.setAbsolutePosition(-30, 200); image.scalePercent(80); content.addImage(image); content.endText(); } stamper.close(); } catch (Exception e) { e.printStackTrace(); } } }
7. ftl文件(模板文件)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>打印预览</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> ...... </head> <body> </body> </html>
预览效果:
打印效果:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持小牛知识库!
本文向大家介绍Android实现PDF预览打印功能,包括了Android实现PDF预览打印功能的使用技巧和注意事项,需要的朋友参考一下 最近在做一个项目,需要用到android手机连接打印机进行打印的功能,目前在网上找到的教程介绍的都是蓝牙连接热敏打印机(pos机大小的打印机)和蓝牙打印机,如果连接日常所见到的网络打印机,进行打印,很显然这些教程是做不到的。 由于android没有提供任何标准,都
本文向大家介绍vue实现在线预览pdf文件和下载(pdf.js),包括了vue实现在线预览pdf文件和下载(pdf.js)的使用技巧和注意事项,需要的朋友参考一下 最近做项目遇到在线预览和下载pdf文件,试了多种pdf插件,例如jquery.media.js(ie无法直接浏览) 最后选择了pdf.js插件(兼容ie10及以上、谷歌、安卓,苹果) 强烈推荐改插件,以下介绍用法 (1)下载插件 下载路
我知道有很多这样的问题,但从我的研究中,没有什么可以解决在Chrome中抑制PDF查看的问题,以及C# Chromedriver的当前状态。 如果我禁用ChromePDF查看器插件并在命令行中执行--disable-print-preview,我可以让测试手动工作,但我没有设法让任何东西在Selenium中工作。 我试过chromeOptions.AddUserProfilePreference(
最后,我们要给绘图程序增加打印和打印预览功能。我们希望文档分两页打印,第一页为封面,打印文档名字。第二页输出文档内容,并在页眉上打印文档名字。虽然AppWizard已经自动生成了打印和打印预览的代码,但是许多情况下,并不能符合要求。 这是因为: 1.打印机和窗口(屏幕)显示的分辨率不同:打印机的分辨率用每英寸多少个点来描述,屏幕分辨率用单位面积的像素点来表示。对于同样的Arial字体下的一个字
本文向大家介绍js实现局部页面打印预览原理及示例代码,包括了js实现局部页面打印预览原理及示例代码的使用技巧和注意事项,需要的朋友参考一下 最近有朋友问js 如何打印预览,今天就来讲解一下,首先了解一下打印原理,其实局部打印页面很简单。就是把你需要打印的部分做一个起始标记,至于标记如何写,随便你写什么。我这里就写 <!--startprint--> 需要打印的内容 <!--endprint-->.
我有一个打印PDF的java程序。它使用Apache PDFBox创建一个对象(在某些情况下来自pdf文档或流),然后使用API将其发送到打印机: 现在我需要能够告诉打印机装订东西。。。 我熟悉javax.print.attributesAPI,并成功地使用它来指定托盘或设置双工,例如: 我知道装订有一个属性: 我有一个施乐Versalink B7035,带有Finisher XL附件,完全支持装