package com.powernode.qrcode.servlet;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/generateWithLogo")
//fileSizeThreshold文件大小达到后自动上传
//maxFileSize最大文件大小
//maxRequestSize最大请求大小
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 10,maxFileSize = 1024 * 1024 * 10,maxRequestSize = 1024 * 1024 * 10)
public class GenerateWithLogo extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取文本内容
String url = request.getParameter("url");
try{
// 使用谷歌提供的ZXING
// 需要创建一个Map集合存储二维码相关的属性
Map map = new HashMap();
// 设置二维码的误差校正级别
// 可选值如下L(7%),M(15%),Q(25%),H(30%)
// 容错率越高消耗资源越多
map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置二维码的字符集
map.put(EncodeHintType.CHARACTER_SET,"UTF-8");
// 设置二维码的四周留白
map.put(EncodeHintType.MARGIN,1);
// 创建ZXING核心对象
// 通过这个对象来生成二维码
MultiFormatWriter writer = new MultiFormatWriter();
// 需要的参数如下,内容,什么格式的二维码,二维码宽度,二维码高度,二维码参数
// BarcodeFormat翻译为条形码格式,通过这个对象来设置格式
// 如QrCode二维码,具有数据密度高可靠性强的特点
// AztecCode高密度可靠性强低容错率更小的尺寸,更高的效率(常用于个人信息账号信息,个人密码)
// PDF417是一种储存大量信息的二维码格式(用于航空机票,运输配送,法律文件等)
// DataMatrix是一种小巧的二维码格式,编码方式类似于QrCode二维码,但是可靠性识别率扫描速度都更优秀,尺寸小,可靠性高,因此多用于嵌入简单的产品标签
// 医疗图像监测数据等方面
BitMatrix bitMatrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300, map);
// 返回一个位矩阵对象(对象内部其实是一个二维数组,二维数组中每一个元素是Boolean类型,true代表黑色,false代表白色)
// 获取矩阵的宽度
int width = bitMatrix.getWidth();
// 获取矩阵的高度
int height = bitMatrix.getHeight();
// 生成二维码图片
// 这个对象是awt.image包下的专门用来生成图片的缓冲对象
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
// 编写一个嵌套循环,遍历二维数组的循环,遍历这个位矩阵对象
for (int x = 0; x < width; x++) {
// 按这个矩阵的高度和宽度遍历一遍
for (int y = 0; y < height; y++) {
// 0xFF000000是黑色,0xFFFFFFFF是白色
image.setRGB(x,y,bitMatrix.get(x,y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
// 给二维码添加LOGO
// 将LOGO缩放
// 每一个文件我们都叫做一个part对象
Part logo = request.getPart("logo");
// 获取我们前端上传的图片文件的输入流
InputStream inputStream = logo.getInputStream();
// 通过IO流读取的方式将图片以流的形式获取
Image logoImage = ImageIO.read(inputStream);
// 对获取到的图片进行缩放
int logoWidth = logoImage.getWidth(null);
int logoHeight = logoImage.getHeight(null);
if (logoWidth > 60) {
logoWidth = 60;
}
if (logoHeight > 60) {
logoHeight = 60;
}
// 这一段代码用来实现缩放
// 使用平滑缩放算法对原始LOGO图像进行缩放得到新的图像
Image scaledInstance = logoImage.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
// 第二部分将缩放完成的LOGO放到二维码上
// 获取2D画笔
Graphics2D graphics = image.createGraphics();
// 指定开始坐标和X和Y
int x = (300 - logoWidth) / 2;
int y = (300 - logoHeight) / 2;
// 将缩放之后的LOGO放上去
graphics.drawImage(scaledInstance,x,y,null);
// 创建一个具有指定位置,高度,圆角半径的圆角矩形,用它来绘制图片的边框
Shape shape = new RoundRectangle2D.Float(x,y,logoWidth,logoHeight,10,10);
// 使用一个宽度为4像素的基本笔触
graphics.setStroke(new BasicStroke(4f));
// 给LOGO画上圆角矩形
graphics.draw(shape);
// 关闭画笔
graphics.dispose();
// 将图片响应回到客户端,Tomcat会自动关闭这个流
ImageIO.write(image,"PNG",response.getOutputStream());
}
catch(Exception e){
e.printStackTrace();
}
}
}