以前打印相信很多人因为A4打印两个报告头大过,M要把一堆报告既有A4的也有A5的还有微生物的,可能输出Page还不那么严谨。要么换页不对叠加了、要么多空白页、中间夹杂A4报告就更加头大。也有的人为了打印页码的共几页而头大。
借助新设计的优势,一举解决痛点问题:
多输出PAGE导致空白页的协议优化
A4打印两个的协议约定
文本背景的协议约定
PDF的协议约定
页码的约定
约定封装
/**
* 控制打印用A4打印两个的模式,业务只需要确保第一个或第二个元素是该元素即可达到A4打印两个的效果
* @param A4Last 如果打印包含A4纸的话是把A4往后移还是不打乱顺序的合并A4前后的A5打印
* @return
*/
public static PrintElement A4Double(boolean A4Last) {
PrintElement ret = new PrintElement();
ret.PrintType = "A4DOUBLE";
if(A4Last==true)
{
ret.PrintFlag="Last";
}
return ret;
}
/**
* 输出页码元素
*
* @param x x坐标(*必填)
* @param y y坐标(*必填)
* @param format 格式串,给空为:第{curnum}页,共{allnum}页 其他自己控制占位符
* @param font 字体
* @param fontSize 字体大小
* @param fontStyle 字体样式
* @param alignment 字体靠齐方向 Center:居中 Right:靠右 Justified或者空:靠左
* @param color 颜色,html颜色 red #ffffff这种
* @param colorBK 背景颜色,html颜色 red #ffffff这种,正常不给
* @param angle 旋转角度,角度数字
* @return
*/
public static PrintElement DrawPageNum(int x, int y, String format, String font, Integer fontSize, String fontStyle, PrintAlignment alignment, String color, String colorBK, String angle) {
PrintElement ret = new PrintElement();
ret.PrintX = String.valueOf(x);
ret.PrintY = String.valueOf(y);
//默认值
if (format == null || format.isEmpty()) {
format = "第{curnum}页,共{allnum}页";
}
ret.PrintText = format;
ret.PrintFont = font;
if (fontSize == null) {
fontSize = 9;
}
ret.PrintFontSize = String.valueOf(fontSize);
ret.PrintFontStyle = fontStyle;
if (color == null) {
color = "";
}
ret.PrintColor = color;
if (colorBK != null && !colorBK.isEmpty()) {
ret.PrintColor = ret.PrintColor + "^" + colorBK;
}
if (alignment != null) {
ret.PrintAlignment = alignment.toString();
}
ret.Angle = String.valueOf(angle);
ret.PrintType = "PAGENUM";
return ret;
}
/**
* 画标签
*
* @param x x坐标(*必填)
* @param y y坐标(*必填)
* @param drawStr 要绘制的文本(*必填)
* @param font 字体
* @param fontSize 字体大小
* @param fontStyle 字体样式
* @param alignment 字体靠齐方向 Center:居中 Right:靠右 Justified或者空:靠左
* @param color 颜色,html颜色 red #ffffff这种
* @param colorBK 背景颜色,html颜色 red #ffffff这种,正常不给
* @param angle 旋转角度,角度数字
* @return
*/
public static PrintElement DrawLabel(int x, int y, String drawStr, String font, Integer fontSize, String fontStyle, PrintAlignment alignment, String color, String colorBK, String angle) {
PrintElement ret = new PrintElement();
ret.PrintX = String.valueOf(x);
ret.PrintY = String.valueOf(y);
ret.PrintText = drawStr;
ret.PrintFont = font;
if (fontSize == null) {
fontSize = 9;
}
ret.PrintFontSize = String.valueOf(fontSize);
ret.PrintFontStyle = fontStyle;
if (color == null) {
color = "";
}
ret.PrintColor = color;
if (colorBK != null && !colorBK.isEmpty()) {
ret.PrintColor = ret.PrintColor + "^" + colorBK;
}
if (alignment != null) {
ret.PrintAlignment = alignment.toString();
}
ret.Angle = String.valueOf(angle);
ret.PrintType = "Label";
return ret;
}
/**
* PDF文件的ftp或http全路径。用英文逗号分隔两个A5PDF路径打印会自动合并为一个A4。一个A5路径后跟个英文逗号,会把PDF转A4纸打印.单独调用打印。
*
* @param httpOrFtpPath pdf文件的下载路径
* @return
*/
public static PrintElement DrawFile(String httpOrFtpPath) {
PrintElement ret = new PrintElement();
ret.DataField = httpOrFtpPath;
ret.PrintType = "FILE";
return ret;
}
/**
* PDF文件的ftp或http全路径。用英文逗号分隔两个A5PDF路径打印会自动合并为一个A4。一个A5路径后跟个英文逗号,会把PDF转A4纸打印,会把PDF每页提取成大图当一页打印
*
* @param httpOrFtpPath pdf文件的下载路径
* @return
*/
public static PrintElement DrawPDF(String httpOrFtpPath) {
PrintElement ret = new PrintElement();
ret.DataField = httpOrFtpPath;
ret.PrintType = "PDF";
return ret;
}
实现A4Double和忽略空PAGE
/**
* 构造函数,在这里就把切页处理好,避免老模式分页逻辑太复杂,简化后续操作
*
* @param elementList
* @return 返回页数,打印页的时候下标从0开始
*/
public int JRTPrintDrawInit(List<DrawElement> elementList) {
if (elementList != null && elementList.size() > 0) {
List<DrawElement> onePage = new ArrayList<>();
for (DrawElement ele : elementList) {
//控制打印机的元素不用管
if (ele.PrintType.contains("PRINTER")) {
continue;
}
//控制打印PDF的元素不用管
if (ele.PrintType.contains("FILE")) {
AllPDFFile.add(ele);
continue;
}
//A4打印两个的模式
if (ele.PrintType.contains("A4DOUBLE")) {
//A4打印两个A5模式
isA4Double=true;
if(ele.PrintFlag.equals("Last"))
{
//A4移到最后
isA4ToLast=true;
}
continue;
}
//按照页切割
if (ele.PrintType.equals("PAGE") || ele.PrintType.equals("PDF")) {
//剔除空白页,让业务可以不那么容易出空白页
if (onePage.size() > 0) {
allPageData.add(onePage);
//存每页纸张的判断
if(pageMaxPrintY>587) {
pagePaper.add("A4");
}
else
{
pagePaper.add("A5");
}
pageMaxPrintY=0;
}
onePage = new ArrayList<>();
}
//打印PDF文件的元素元素
if (ele.PrintType.equals("PDF")) {
JRTPrintDraw.FileService fileService = new JRTPrintDraw.FileService();
InputStream stream = null;
try {
//从文件服务里面下载文件
if (ele.PrintImageFile == "1") {
stream = fileService.DownloadStream(ele.DataField, true);
} else {
stream = fileService.DownloadStream(ele.DataField, false);
}
if (stream != null) {
List<BufferedImage> images = JRTPrintDraw.PDFUtil.GetPDFImage(stream);
stream.close();
if (images != null && images.size() > 0) {
for (BufferedImage img : images) {
DrawElement graph = new DrawElement();
graph.PrintX = String.valueOf(0);
graph.PrintY = String.valueOf(0);
graph.DataField = ImgToBase64(img);
graph.PrintWidth = String.valueOf(img.getWidth() / 5);
graph.PrintHeight = String.valueOf(img.getHeight() / 5);
graph.PrintType = "Graph";
graph.PrintFlag = "D";
onePage.add(graph);
//剔除空白页,让业务可以不那么容易出空白页
if (onePage.size() > 0) {
allPageData.add(onePage);
//存每页纸张的判断
if(img.getHeight() / 5>587) {
pagePaper.add("A4");
}
else
{
pagePaper.add("A5");
}
pageMaxPrintY=0;
}
onePage = new ArrayList<>();
}
}
}
} catch (Exception ex) {
StringWriter stringWriter = new StringWriter();
ex.printStackTrace(new PrintWriter(stringWriter));
WriteLog(stringWriter.toString());
}
continue;
}
//得到最大的Y坐标
DealMaxY(ele);
//不是分页元素才加
if (!ele.PrintType.equals("PAGE")) {
onePage.add(ele);
}
}
if (onePage.size() > 0) {
allPageData.add(onePage);
//存每页纸张的判断
if(pageMaxPrintY>587) {
pagePaper.add("A4");
}
else
{
pagePaper.add("A5");
}
pageMaxPrintY=0;
}
}
//A4打印两个的处理逻辑
if(isA4Double==true)
{
DealA4Double();
}
//设置打印的页面
for(List<DrawElement> onePage:allPageData) {
printPageData.add(onePage);
}
return allPageData.size();
}
/**
* 处理A4打印两个
*/
private void DealA4Double()
{
//存处理的A4打印两个页
List<List<DrawElement>> allA4DoublePape = new ArrayList<>();
//临时放A4后移的页
List<List<DrawElement>> a4LastPageTmp = new ArrayList<>();
int index=-1;
//当前添加A5到一页的数量
int addA5Num=0;
//合并一页用的临时数组
List<DrawElement> mergePageTmp=new ArrayList<>();
for(List<DrawElement> onePage:allPageData)
{
index++;
String paper=pagePaper.get(index);
//A4页处理
if(paper.equals("A4"))
{
//中间的A4后移
if(isA4ToLast==true)
{
a4LastPageTmp.add(onePage);
}
else
{
//如果有合并的页就终止
if(mergePageTmp.size()>0) {
//合并满一页开始新的一页
allA4DoublePape.add(mergePageTmp);
mergePageTmp = new ArrayList<>();
addA5Num = 0;
}
allA4DoublePape.add(onePage);
}
}
//A5页处理
else
{
addA5Num++;
//上半页
if(addA5Num==1)
{
MergePage(mergePageTmp,onePage,false);
}
//下半页
else if(addA5Num==2)
{
MergePage(mergePageTmp,onePage,true);
//如果有合并的页就终止
if(mergePageTmp.size()>0) {
//合并满一页开始新的一页
allA4DoublePape.add(mergePageTmp);
mergePageTmp = new ArrayList<>();
addA5Num = 0;
}
}
}
}
//如果有合并的页就终止
if(mergePageTmp.size()>0) {
//合并满一页开始新的一页
allA4DoublePape.add(mergePageTmp);
mergePageTmp = null;
addA5Num = 0;
}
//后移的A4合并进主数据
if(a4LastPageTmp.size()>0)
{
for(List<DrawElement> onePage:a4LastPageTmp)
{
allA4DoublePape.add(onePage);
}
}
//替换主数据
allPageData=allA4DoublePape;
allA4DoublePape=null;
a4LastPageTmp=null;
}
/**
* 合并页数据
* @param mergeTmp 合并的临时数据
* @param addPage 要并入的页
* @param addY 是否添加y,是就是A4下面
*/
private void MergePage(List<DrawElement> mergeTmp,List<DrawElement> addPage,boolean addY)
{
//不添加Y的话就原封不动的转移
if(addY==false)
{
if(addPage!=null&&addPage.size()>0)
{
for(DrawElement ele:addPage)
{
mergeTmp.add(ele);
}
}
}
//A4下半页偏移Y坐标
else
{
if(addPage!=null&&addPage.size()>0)
{
for(DrawElement ele:addPage)
{
ele.PrintY=String.valueOf(DrawConvert.ToInt32(ele.PrintY)+583);
//线的终点的Y坐标
if(ele.PrintType.equals("ILineN"))
{
ele.PrintHeight=String.valueOf(DrawConvert.ToInt32(ele.PrintHeight)+583);
}
//多边形的Y坐标
if(ele.PrintType.equals("Poly"))
{
String [] arr=ele.PrintText.split("\\^");
String polyStr = "";
for(String s:arr)
{
String [] arr1=s.split("@");
if (polyStr.isEmpty()) {
polyStr = arr1[0] + "@" + String.valueOf(DrawConvert.ToInt32(arr[1])+583);
} else {
polyStr += "^" + arr1[0] + "@" + String.valueOf(DrawConvert.ToInt32(arr[1])+583);
}
}
ele.PrintText=polyStr;
}
mergeTmp.add(ele);
}
}
}
}
打印示例代码
import JRT.Core.Dto.OutParam;
import JRT.Core.Dto.OutValue;
import JRT.Core.Dto.PrintElement;
import JRT.Core.Util.PrintDrawProtocol;
import JRTBLLBase.BaseHttpHandlerNoSession;
import JRTBLLBase.Helper;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* 输出符合打印元素绘制协议的打印元素数据,来供打印执行层打印
*/
public class PrintBarCodeTest extends BaseHttpHandlerNoSession {
/**
* 按传入的RowID输出符合打印元素绘制协议的数据来实现打印控制
* @param RowID 业务主键
* @param P1
* @param P2
* @param P3
* @param P4
* @param P5
* @param P6
* @param P7
* @param P8
* @param P9
* @param P10
* @param P11
* @param P12
* @param P13
* @param Session
* @param Output
* @return
*/
public String GetData(String RowID, String P1, String P2, String P3, String P4, String P5, String P6, String P7, String P8, String P9, String P10, String P11, String P12, String P13, OutValue Session, OutValue Output) throws Exception{
List<PrintElement> retList=new ArrayList<>();
//标志A4打印两个
retList.add(PrintDrawProtocol.A4Double(true));
//打印PDF文件
//retList.add(PrintDrawProtocol.DrawFile("http://localhost:8080/JRTWeb/FileService/test.pdf"));
retList.add(PrintDrawProtocol.DrawPDF("http://localhost:8080/JRTWeb/FileService/test.pdf"));
//换页
retList.add(PrintDrawProtocol.ChangePage());
//换页
retList.add(PrintDrawProtocol.ChangePage());
//换页
retList.add(PrintDrawProtocol.ChangePage());
//页码
retList.add(PrintDrawProtocol.DrawPageNum(720,10,"","宋体",12,"", null,"","#fda632","0"));
//画logo
retList.add(PrintDrawProtocol.DrawLabel(420,10,"http的logn图","宋体",22,"", null,"","#fda632","0"));
retList.add(PrintDrawProtocol.DrawGraph(420,30,64,64,"http://localhost:8080/JRTWeb/FileService/logo.png",false,null));
retList.add(PrintDrawProtocol.DrawLabel(420,150,"ftp的logn图","宋体",12,"", null,"","#fda632","0"));
//retList.add(PrintDrawProtocol.DrawGraph(420,180,64,64,"ftp://zlz:zlz@127.0.0.1:21/ftp.png",false,null));
//画一个文本
retList.add(PrintDrawProtocol.DrawLabel(20,20,"zhanglianzhu","宋体",12,"", null,"","#ff5252","0"));
//画一个条码
retList.add(PrintDrawProtocol.DrawBarCode(20,50,"0947809",true,5,30,"","宋体",12,"",null,"","0"));
//换一根横线
retList.add(PrintDrawProtocol.DrawLine(20,70,70,70,1,"",""));
//换一根竖线
retList.add(PrintDrawProtocol.DrawLine(50,10,50,470,1,"",""));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawQRCode(20,90,"jbase",90,90));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(20,210,"jbase打印支持","宋体",12,"",null,"","","0"));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(20,230,"20231118 22:49","宋体",12,"",null,"","","0"));
//画一个点
retList.add(PrintDrawProtocol.DrawPoint(20,270,10,10,"o",""));
retList.add(PrintDrawProtocol.DrawPoint(100,270,10,10,"[]",""));
retList.add(PrintDrawProtocol.DrawPoint(200,270,10,10,"<>",""));
//画多边形
List<Point> pointList=new ArrayList<>();
Point p1=new Point();
p1.x=10;
p1.y=300;
pointList.add(p1);
Point p2=new Point();
p2.x=100;
p2.y=310;
pointList.add(p2);
Point p3=new Point();
p3.x=50;
p3.y=360;
pointList.add(p3);
retList.add(PrintDrawProtocol.DrawPoly(pointList,""));
//画复选框
retList.add(PrintDrawProtocol.DrawCheckBox(10,400,true,30,30));
//画单选框
retList.add(PrintDrawProtocol.DrawRadio(60,400,true,30,30));
//画复选框
retList.add(PrintDrawProtocol.DrawCheckBox(110,400,false,30,30));
//画单选框
retList.add(PrintDrawProtocol.DrawRadio(160,400,false,30,30));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(20,1010,"页尾","宋体",12,"",null,"","","0"));
retList.add(PrintDrawProtocol.DrawLabel(20,900,"A4纸张打印","宋体",12,"", null,"","","0"));
//换一根横线
retList.add(PrintDrawProtocol.DrawLine(20,1025,700,1025,1,"",""));
//换页
retList.add(PrintDrawProtocol.ChangePage());
//页码
retList.add(PrintDrawProtocol.DrawPageNum(520,10,"","宋体",12,"", null,"","#fda632","0"));
//画logo
retList.add(PrintDrawProtocol.DrawLabel(420,10,"logn图","宋体",12,"", null,"","","0"));
retList.add(PrintDrawProtocol.DrawGraph(420,20,64,64,"http://localhost:8080/JRTWeb/FileService/logo.png",false,null));
//画一个文本
retList.add(PrintDrawProtocol.DrawLabel(10,10,"这是打印的第二页","宋体",12,"", null,"","","0"));
//画一个条码
retList.add(PrintDrawProtocol.DrawBarCode(10,50,"0947809",true,5,30,"","宋体",12,"",null,"","0"));
//换一根横线
retList.add(PrintDrawProtocol.DrawLine(10,70,70,70,1,"",""));
//换一根竖线
retList.add(PrintDrawProtocol.DrawLine(50,10,50,470,1,"",""));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawQRCode(10,90,"jbase",90,90));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,210,"jbase打印支持","宋体",12,"",null,"","","0"));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,230,"20231119","宋体",12,"",null,"","","0"));
retList.add(PrintDrawProtocol.DrawLabel(20,500,"A5纸张打印","宋体",12,"", null,"","","0"));
//画一根横线
retList.add(PrintDrawProtocol.DrawLine(20,525,700,525,1,"",""));
//换页
retList.add(PrintDrawProtocol.ChangePage());
//页码
retList.add(PrintDrawProtocol.DrawPageNum(520,10,"","宋体",12,"", null,"","#fda632","0"));
//画logo
retList.add(PrintDrawProtocol.DrawLabel(420,10,"logn图","宋体",12,"", null,"","","0"));
retList.add(PrintDrawProtocol.DrawGraph(420,20,64,64,"http://localhost:8080/JRTWeb/FileService/logo.png",false,null));
//画一个文本
retList.add(PrintDrawProtocol.DrawLabel(10,10,"这是打印的第三页","宋体",12,"", null,"","","0"));
//画一个条码
retList.add(PrintDrawProtocol.DrawBarCode(10,50,"0947809",true,5,30,"","宋体",12,"",null,"","0"));
//换一根横线
retList.add(PrintDrawProtocol.DrawLine(10,70,70,70,1,"",""));
//换一根竖线
retList.add(PrintDrawProtocol.DrawLine(50,10,50,470,1,"",""));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawQRCode(10,90,"jbase",90,90));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,210,"jbase打印支持","宋体",12,"",null,"","","0"));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,230,"20231119","宋体",12,"",null,"","","0"));
retList.add(PrintDrawProtocol.DrawLabel(20,500,"A5纸张打印","宋体",12,"", null,"","","0"));
//画一根横线
retList.add(PrintDrawProtocol.DrawLine(20,525,700,525,1,"",""));
//换页
retList.add(PrintDrawProtocol.ChangePage());
//页码
retList.add(PrintDrawProtocol.DrawPageNum(520,10,"","宋体",12,"", null,"","#fda632","0"));
//画logo
retList.add(PrintDrawProtocol.DrawLabel(420,10,"logn图","宋体",12,"", null,"","","0"));
retList.add(PrintDrawProtocol.DrawGraph(420,20,64,64,"http://localhost:8080/JRTWeb/FileService/logo.png",false,null));
//画一个文本
retList.add(PrintDrawProtocol.DrawLabel(10,10,"这是打印的第四页","宋体",12,"", null,"","","0"));
//画一个条码
retList.add(PrintDrawProtocol.DrawBarCode(10,50,"0947809",true,5,30,"","宋体",12,"",null,"","0"));
//换一根横线
retList.add(PrintDrawProtocol.DrawLine(10,70,70,70,1,"",""));
//换一根竖线
retList.add(PrintDrawProtocol.DrawLine(50,10,50,470,1,"",""));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawQRCode(10,90,"jbase",90,90));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,210,"jbase打印支持","宋体",12,"",null,"","","0"));
//绘制一个条码
retList.add(PrintDrawProtocol.DrawLabel(10,230,"20231206","宋体",12,"",null,"","","0"));
retList.add(PrintDrawProtocol.DrawLabel(20,500,"A5纸张打印","宋体",12,"", null,"","","0"));
//画一根横线
retList.add(PrintDrawProtocol.DrawLine(20,525,700,525,1,"",""));
//先包一个打印元素绘制协议数据生成的工具类来解决元素约束问题,工具类实现了调用工具类得到标签,条码,文本等
return Helper.Object2Json(retList);
}
}
让独立的A4后移
不扰乱顺序
这样就能极大的简化业务的打印控制逻辑,方便得到高效稳定的打印效果,后面有时间将解决绘制表格的痛点问题来给Web提供强大的客户端支持,这是一次没有历史代码干扰的全新设计,也是对老效果的全面超越 哈哈