其实做开发这么久以来,我接触到的东西都不算全面,甚至知识面还是比较窄的!今天接到了一个比较有意思的项目,用后端代码画图,在我的印象中,后端的图片来源应该都是前端,或者UI,再不济,后端动态取值,给前端来排版展示!
但是今天,我的这个功能结束了,我做到了后端取值,自己排版!生成图片!
当然,其实这个其实并不复杂,而且大多数人都在用!下面就看要做哪些准备工作吧!
public InputStream shareQdlPoster(String headImg, String share_txt,
String qrcode, int hasSign,String brandName,String backGround,Map<String,Object> param){
ByteArrayOutputStream os = null;
InputStream is = null;
InputStream result = null;
try {
BufferedImage buffImg=null;
result = getURLInputStream(backGround);
buffImg = Thumbnails.of(result).scale(0.5f).outputQuality(1f).asBufferedImage();
Graphics g = buffImg.getGraphics();// 得到画笔对象
if(headImg!=null&&!"".equals(headImg)){
//用户头像
BufferedImage img = roundImg(headImg, 160, 160);
g.drawImage(img,737,142,398,398,null);
}
//商品图
if(param!=null&&!param.isEmpty()){
BufferedImage imgCover = ImageIO.read(getURLInputStream(Tools.toString(param.get("goodsImage"))));
g.drawImage(imgCover,395,1080,1100,1100,null);
}
//赞助商名称
g.setColor(Color.GRAY);
g.setFont(new Font("苹方-简", Font.BOLD, 60));
g.drawString(brandName+"赞助", 830, 2280);
//连续签到天数
g.setColor(Color.RED);
g.setFont(new Font("Arial", Font.PLAIN, 250));
g.drawString(Tools.toString(hasSign), 1150,830);
//仍缺天数
g.setColor(Color.WHITE);
g.setFont(new Font("苹方-简", Font.BOLD,75));
g.drawString(share_txt, 400, 980);
//活动时间
if(param!=null&&!param.isEmpty()){
g.setColor(Color.WHITE);
g.setFont(new Font("苹方-简", Font.BOLD, 50));
g.drawString("活动时间:"+Tools.toString(param.get("getTime")), 300, 2480);
}
//领取地址
if(param!=null&&!param.isEmpty()){
g.setColor(Color.WHITE);
g.setFont(new Font("苹方-简", Font.BOLD, 50));
String addr=Tools.toString(param.get("getAddr"));
if(addr.length()>18){
String firstRow=addr.substring(0,18);
String secondRow=addr.substring(18);
g.drawString("领取地址:"+firstRow, 300, 2550);
g.drawString(secondRow, 500, 2610);
}else {
g.drawString("领取地址:"+addr,300, 2550);
}
}
// 小程序二维码
BufferedImage imgQrcode = new ImageUtil().roundImg(qrcode, 160, 160);
g.drawImage(imgQrcode,1250,2800,400,400, null);
g.dispose();
os = new ByteArrayOutputStream();
ImageIO.write(buffImg, "jpg", os);
is = new ByteArrayInputStream(os.toByteArray());
} catch (Exception e) {
e.printStackTrace();
}finally{
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(result);
}
return is;
}
很明显,这个类返回的是一个inputStream的流!在类里面,我们既能对文字进行排版操作,也能对图片进行排版操作。
比如:Thumbnails这个方法是处理图片综合比例和大小的
roundImg 是对图像进行圆角处理,其原理就是透明化周边角
getURLInputStream 是对传进来的url参数进行读取,所以从这里我们知道,图片必须是能读取出来的url。
等等还有很多,可以自己追寻源码或者百度!这里我还可以提供一个头像圆角处理的方法
/**
* 把头像裁剪成圆形
* @param headImg doamin + path
* @return
*/
public BufferedImage roundImg(String headImg,int width, int height) {
if (StringUtils.isBlank(headImg)) {
return null;
}
InputStream result = null;
try {
result = getURLInputStream(headImg);
BufferedImage bi1 = ImageIO.read(result);
BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, bi1.getWidth(), bi1
.getHeight());
Graphics2D g2 = bi2.createGraphics();
// g2.setBackground(Color.WHITE);
g2.setColor(new Color(0,0,0,0));
g2.fill(new Rectangle(bi2.getWidth(), bi2.getHeight()));
g2.setClip(shape);
// 使用 setRenderingHint 设置抗锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(bi1, 0, 0, null);
g2.dispose();
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
ImageIO.write(bi2, "png", imOut);
InputStream is = new ByteArrayInputStream(bs.toByteArray());
BufferedImage buffImg = ImageIO.read(is);
return zoomInImage(buffImg,width,height);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally{
IOUtils.closeQuietly(result);
}
return null;
}
怎么获取https或者http中的url数据,方法咱们也有参考:
/**
* 获取https或http的URL数据
* @param u
* @return
* @throws Exception
*/
public static InputStream getURLInputStream(String u) throws Exception{
URL url = new URL(u);
String host = url.getProtocol() + "://" + url.getHost();
String path = u.replaceAll(host,"");
HttpResponse resp = HttpUtils.doGet(host, path, "GET", new HashMap<String, String>(), new HashMap<String, String>());
InputStream result = resp.getEntity().getContent();
return result;
}
其实我们再对图片进行处理的过程中,还会涉及到图片的尺寸问题,在这里,我也只封装了一个改变图片high,width的方法:
/**
* 改变图片尺寸
*
* @param imgUrl 图片的路径 domail + path
* @param width 修改后的宽度
* @param height 修改后的高度
* @return BufferedImage对象
*/
public BufferedImage getBufferedImage(String imgUrl, int width, int height) {
if (StringUtils.isBlank(imgUrl)) {
return null;
}
InputStream result = null;
try {
result = getURLInputStream(imgUrl);
BufferedImage bi = ImageIO.read(result);
BufferedImage tag = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
tag.getGraphics().drawImage(bi, 0, 0, bi.getWidth(), bi.getHeight(), null);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
ImageIO.write(tag, "jpg", imOut);
InputStream is = new ByteArrayInputStream(bs.toByteArray());
BufferedImage buffImg = ImageIO.read(is);
return zoomInImage(buffImg,width,height);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally{
IOUtils.closeQuietly(result);
}
return null;
}
当然,在这里,能操作的前提肯定是图片已经存到服务器中,再不济也应该是我们自己的tomcat服务器中。下面还会解释一下,怎么拼接域名,怎么存储图片!
InputStream ips=null;
//开始生成海报--------------------------------------------------------------------------------------
if (goods!=null&&!goods.isEmpty()) {
//输出海报图片
ips = new ImageUtil().shareQdlPoster(headImg,share_txt,qrPath,has_sign,brandName,backGroundImage,goods);
}
if(ips!=null){
filePath = FileUtil.saveFile(ips, getProperties("file.root"), "share", "share.jpg");
}
IOUtils.closeQuietly(ips);
这里可以再详细的介绍一下saveFile这个具体的存储方法
/**
* 上传文件
* @param excelFile 文件
* @param fileRootPath ROOT_PATH路径
* @param fileBusiType 文件业务类型
* @param fileName 文件名
* @return
* @throws Exception
*/
public static String saveFile(InputStream in,String fileRootPath,String fileBusiType,String fileName) throws Exception {
String uploadFileName = Tools.replaceLine(Tools.uuid()) + fileName.substring(fileName.lastIndexOf(".")); // UUID生成文件名
String location = FileStore.saveFile(in, fileBusiType,fileRootPath,uploadFileName);
return location;
}
这里中间过渡一段,saveFile的具体实现内容在下面
/**
* 保存文件至文件服务器
* @param in 数据输入流
* @param fileName 文件名
* @return 文件相对路径
* @throws SQLException
* @throws IOException
*/
public static String saveFile(InputStream in,String fileCategory,String fileRootPath, String fileName) throws Exception{
//创建目录
String relaPath = getRelaPath(fileCategory);
File path = new File(fileRootPath, relaPath);
if (!path.exists() || !path.isDirectory()){
path.mkdirs();
}
//创建文件
String location = relaPath + fileName;
File file = new File(fileRootPath, location);
// File file = MyFile.newInstance(fileRootPath,location);
FileOutputStream out = new FileOutputStream(file);
try{
rw(in, out);
}finally{
try{
out.close();
}catch(Exception ex){
}
}
return location;
}
这也是一个通过文件流来新建文件夹,或者寻找文件夹。
以上不进详细,仅供参考,也作为我个人的一个线上笔记!