最近因为java项目中有大量的图片需要导出到word(采用freemarker导出模板),导出的过程中发现一个问题:导出饼图的时候会随着浏览器的大小不同被拉长或者拉伸,查阅很多质料但网上并没有找到相关的解决办法,因此今日记录下来以便以后查阅,同时也将解决思路分享给大家,有问题的地方希望有机会看到文章的技术大咖给以指导。
1、要点及思路
(1)word模板修改后将如果图片的单位是厘米则修改为像素(修改方法网上有)或者自己算出对应的像素,且以下计算已像素为准
(2)word文档另存为xml文件,此时打开可看到图片的一些设置 关键行
设置图片的宽高
(3)cx,cy计算公式如下
公式:实际width=cX*100/914400;//固定系数
实际height=cY*100/914400;//固定系数
(4)java项目将图片放大或缩小的的思路是获取图片宽度和高度,乘以倍数得出新的宽度和高度
因此解决该问题的思路转换为
第一步:前端获取实际图片的宽度高度传入后台,当然也可以java直接是获取图片文件
第二步:传入设置宽度和高度,即是上面提到的word里图片设置的像素
第二步:根据实际宽度高度和设置宽度高度计算缩放比例,得出目标宽度高度
第四步:根据以上公式,实际wideth即是现在的目标宽度,高度一样的,计算出目标CX,CY
第五步:将该CX,CY套入xml文件关键行 ,即是
此时你可能会发现,如果本来实际宽度和实际高度已经小于设置宽度和高度,图片会被缩放的很小,因此,再对小于设置宽度或高度的图片做等比放大,以宽度位置还是高度位置取决于你自己因此:
第六步:选择性的等比放大目标宽度和高度,放大到合适大小
2、具体代码如下:
/**
* 设置图片宽高(以纸张设置A4为标准,宽高单位像素)
* @param imWidth 实际宽度
* @param imHeight 实际高度
* @param sWidth 设置宽度
* @param sHeight 设置
*@param iType 图片类型 已混搭图 和饼图为例
* @param isEnlarge 是否放大 0-不放大,1-放大 选择性的放大图片
* @remarks 当 实际宽高小于目标设置宽高时等比缩小后word展示的图片过小,此时下可设置等比放大,放大到合适大小
* @return
*/
public static Map setWH(String imWidth,String imHeight ,String sWidth,String sHeight,String iType,String isEnlarge){
Map map=new HashMap();
//设置宽高
double width =Double.parseDouble(sWidth);
double height=Double.parseDouble(sHeight);
//实际宽高
double iWidth=Double.parseDouble(imWidth);
double iHeight=Double.parseDouble(imHeight);
//目标宽高
Double tW;
Double tH;
//混搭图宽度比例以0.6作为分界点,小于0.6 会拉长,大于0.6会拉伸,饼图:大于0.7小于1.0时会拉长,大于1.0时会拉伸,次临界点以不同大小屏幕测试得出的计算值
if((width/iWidth<0.6 && "1".equals(imageType)) || (width/iWidth>0.7 && width/iWidth<1.0 && "2".equals(imageType))){
//计算缩放比例
tW=iWidth*(height/iHeight);
tH=iHeight*(height/iHeight);
}else{
//计算缩放比例
if(width/iWidth<=height/iHeight){
tW=iWidth*(width/iWidth);
tH=iHeight*(height/iHeight);
}else{
tW=iWidth*(height/iHeight);
tH=iHeight*(height/iHeight);
}
//选择性的等比放大图片
if("1".equals(isEnlarge)){
//目标宽度或高度小于设置宽度或高度时比例方法
if(tW map=enlWH(tW,tH,width,height);
tW=(Double) map.get("tW");
tH=(Double)map.get("tH");
}
}
}
//图片cX,cY计算
//914400为固定系数
map.put("imageWidth", String.valueOf(tW.intValue()*914400/100));
map.put("imageHeight",String.valueOf((tH.intValue()*914400/100)));
return map;
}
/**
* 比例放大
* @param width 转换过的宽度
* @param height 转换过的高度
* @param MaxWidth 目标宽度
* @param MaxHeight 目标高度
*/
public static Map enlWH(double width,double height,double maxWidth,double maxHeight){
Map map = Maps.newConcurrentMap();
// 放大倍数
double times = 1;
//比例
double sw = (maxWidth * 1.0) / (width * 1.0);
double sh = (maxHeight * 1.0) / (height * 1.0);
if (width > maxWidth && height > maxHeight) {
return map;
} else if (width < maxWidth && height <= maxHeight) {
if (sw > sh) {
times = sw + 0.2;//根据实际情况设置
} else {
times = sh + 0.2;
}
} else if (width < maxWidth && height > maxHeight) {
times = sw + 0.2;
} else {
times = sh + 0.2;
}
NumberFormat nf=NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(1);
times=Double.parseDouble(nf.format(times));
Double lastW = times * width;
Double lastH = times * height;
map.put("tW", lastW);
map.put("tH", lastH);
return map;
}
第一次发表经验,以上只是解决此类问题的一个思路,但不是唯一办法,如有好的方案及思路很感谢一起分享出来,写的有不好地方敬请指正!