package cn.com.yitong.ares.qrcode;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Hashtable;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/**
* 二維碼的工具類
* @author fyh
*
*/
public class ZXingUtil {
//定義int類型的常量用於存放生成二維碼時的類型
private static final int BLACK = 0xFF000000;
private static final int WHITE = 0xFFFFFFFF;
/**
* 加密:文字-->圖片 將文本變成二維數組,
* @param imagePath
* @param format:文件格式及后綴名
* @param content
* @throws WriterException
* @throws IOException
*/
public static void encodeimage(String imagePath , String format , String content , int width , int height , String logo) throws WriterException, IOException{
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType , Object>();
//容錯率:L(7%)<M(15%)<Q(25%)<H(35%);H容錯率最高
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//編碼格式
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//外邊距
hints.put(EncodeHintType.MARGIN, 1);
/***
* BarcodeFormat.QR_CODE:解析什么類型的文件:要解析的二維碼的類型
* content:解析文件的內容
* width:生成二維碼的寬
* height:生成二維碼的高
* hints:涉及到加密用到的參數: 即 編碼 和容錯率
*/
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height , hints);
//使BufferedImage勾畫QRCode (matrixWidth 是行二維碼像素點)
int matrixWidth = bitMatrix.getWidth();
/**
* 內存中的一張圖片:是RenderedImage的子類,而RenderedImage是一個接口
* 此時需要的圖片是一個二維碼-->需要一個boolean[][]數組存放二維碼 --->Boolean數組是由BitMatrix產生的
* BufferedImage.TYPE_INT_RGB : 表示生成圖片的類型: 此處是RGB模式
*/
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//生成二維數組
for(int x=0;x<matrixWidth;x++){
for(int y=0 ; y<matrixWidth;y++){
//二維坐標整個區域:畫什么顏色
img.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);
}
}
//畫log
img = logoImg(img, logo);
//將二維碼圖片轉換成文件
File file = new File(imagePath);
//生成圖片
ImageIO.write(img, format, file);
}
/**
* 解密,將生成的二維碼轉換成文字
* @param file:二維碼文件
* @throws Exception
*/
public static String decodeImage(File file) throws Exception{
//首先判斷文件是否存在
if(!file.exists()){
return "";
}
//將file轉換成內存中的一張圖片
BufferedImage image = ImageIO.read(file);
MultiFormatReader formatter = new MultiFormatReader();
LuminanceSource source = new BufferedImageLuminanceSource(image);
Binarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
//將圖片的文字信息解析到result中
Result result = formatter.decode(binaryBitmap);
System.out.println(result.getText());
return result.getText();
}
/**
* 傳logo和二維碼,生成-->帶logo的二維碼
* @param matrixImage :二維碼
* @param logo : 中間的logo
* @return
* @throws IOException
*/
public static BufferedImage logoImg(BufferedImage matrixImage ,String logo) throws IOException{
//在二維碼上畫logo:產生一個二維碼畫板
Graphics2D g2 = matrixImage.createGraphics();
//畫logo,將String類型的logo圖片存放入內存中;即 string-->BufferedImage
BufferedImage logoImage = ImageIO.read(new File(logo));
//獲取二維碼的高和寬
int height = matrixImage.getHeight();
int width = matrixImage.getWidth();
/**
* 純log圖片
* logoImage:內存中的圖片
* 在二維碼的高和寬的2/5,2/5開始畫log,logo占用整個二維碼的高和寬的1/5,1/5
*/
g2.drawImage(logoImage,width*2/5, height*2/5, width*1/5, height*1/5, null);
/**
* 畫白色的外邊框
* 產生一個畫白色圓角正方形的畫筆
* BasicStroke.CAP_ROUND:畫筆的圓滑程度,此處設置為圓滑
* BasicStroke.JOIN_ROUND:在邊與邊的連接點的圓滑程度,此處設置為圓滑
*/
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
//將畫板和畫筆關聯起來
g2.setStroke(stroke);
/**
* 畫一個正方形
* RoundRectangle2D是一個畫長方形的類,folat是他的內部類
*/
RoundRectangle2D.Float round = new RoundRectangle2D.Float(width*2/5, height*2/5, width*1/5, height*1/5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
//設置為畫白色
g2.setColor(Color.WHITE);
g2.draw(round);
//畫灰色的內邊框,原理與畫白色邊框相同
BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g2.setStroke(stroke2);
RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(width*2/5+2, height*2/5+2, width*1/5-4, height*1/5-4,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
//另一種設置灰色的方法:Color color = new Color(128,128,128);其中三個參數是 R G B
g2.setColor(Color.GRAY);
g2.draw(round2);
//釋放內存
g2.dispose();
//刷新二維碼
matrixImage.flush();
return matrixImage;
}
/**
* 沒有logo
*
* @param content 文字→二維碼
* @param path 二維碼圖片儲存位置
* @param format
* @param height2
* @param width2
* @return
*/
@SuppressWarnings("unused")
static
boolean orCode(String content, String path, int width, int height, String format) {
/*
* 圖片的寬度和高度
*/
// int width = 100;
// int height = 100;
// // 圖片的格式
// String format = "png";
// 定義二維碼的參數
HashMap<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
// 定義字符集編碼格式
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
// 糾錯的等級 L > M > Q > H 糾錯的能力越高可存儲的越少,一般使用M
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
// 設置圖片邊距
hints.put(EncodeHintType.MARGIN, 1);
try {
// 最終生成 參數列表 (1.內容 2.格式 3.寬度 4.高度 5.二維碼參數)
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
// 寫入到本地
int matrixWidth = bitMatrix.getWidth();
/**
* 內存中的一張圖片:是RenderedImage的子類,而RenderedImage是一個接口
* 此時需要的圖片是一個二維碼-->需要一個boolean[][]數組存放二維碼 --->Boolean數組是由BitMatrix產生的
* BufferedImage.TYPE_INT_RGB : 表示生成圖片的類型: 此處是RGB模式
*/
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//生成二維數組
for(int x=0;x<matrixWidth;x++){
for(int y=0 ; y<matrixWidth;y++){
//二維坐標整個區域:畫什么顏色
img.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);
}
}
// Path file = new File(path).toPath();
// MatrixToImageWriter.writeToPath(bitMatrix, format, file);
File file = new File(path);
//生成圖片
ImageIO.write(img, format, file);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static BufferedImage compositePicature(String beijingPath,String imagePath,String finalImagePath,String format) {
int fontSize=13;
//在背景里畫二維碼,將String類型的圖片存放入內存中;即 string-->BufferedImage
BufferedImage beijingImage = null;
try {
beijingImage = ImageIO.read(new File(beijingPath));
BufferedImage logoImage = ImageIO.read(new File(imagePath)); //100*100
//獲取二維碼的高和寬
int height = logoImage.getHeight();
int width = logoImage.getWidth();
/**
* 獲取背景圖的高和寬
*/
int height2 = beijingImage.getHeight();
int width2 = beijingImage.getWidth();
Graphics2D g = beijingImage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(logoImage, width2-width-30, height2-height-30, width, height, null);
// 消除文字鋸齒
// g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 在背景添加二維碼圖片(地址,左邊距,上邊距,圖片寬度,圖片高度,未知)
// Font font1 = new Font("微軟雅黑", Font.BOLD, fontSize);// 添加字體的屬性設置
// g.setFont(font1);
// Color color1 = new Color(100,0,0);
// g.drawString("掃碼了解詳情",width2-width+5, height2-10);
// g.drawString("掃碼了解詳情",width2-width+5, height2-10);
// g.setColor(color1);
// 抗鋸齒
Font font = new Font("微軟雅黑", Font.BOLD, 13);
g.setFont(font);
g.setPaint(new Color(0, 0, 0, 64));
// 先繪制一遍底色
g.drawString("掃碼了解詳情", width2-width-20, height2-10);
g.setPaint(new Color(100,0,0));
// 再繪制一遍文字
// 由於部分情況會出現文字模糊的情況,保險起見才出此對策。
g.drawString("掃碼了解詳情", width2-width-20, height2-10);
g.dispose();
//將二維碼圖片轉換成文件
File file = new File(finalImagePath);
//生成圖片
ImageIO.write(beijingImage, format, file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 335*459
return beijingImage;
}
}
package cn.com.yitong.ares.qrcode;
import java.awt.image.BufferedImage;
import java.io.IOException;
import com.google.zxing.WriterException;
import cn.com.yitong.ares.qrcode.ZXingUtil;
import cn.com.yitong.ares.test2.IGraphics2D;
public class ZXingQR_code {
/**
* 生成二維碼(帶內嵌的logo)
* @param imagePath
* @param format
* @param content
* @param width
* @param height
* @param logopath
*/
public void drawWord(String imagePath, String format, String content,int width, int height,String logopath) {
try {
ZXingUtil.encodeimage(imagePath, "JPEG", content, 100, 100 , logopath);
} catch (WriterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 1.生成二維碼 (不帶logo)
* 2. 合並圖片 二維碼圖片和海報圖片
* @param beijingPath
* @param logoPath
* @param imagePath
* @param format
* @param content
*/
public void compositionDrawWord(String url,String imagePath,String beijingPath,String finalImagePath, int width, int height, String format) {
try {
if (ZXingUtil.orCode(url, imagePath, width, height,format)) {
System.out.println("ok,成功");
BufferedImage image=ZXingUtil.compositePicature(beijingPath, imagePath, finalImagePath, format);
} else {
System.out.println("no,失敗");
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static void main(String[] args) throws Exception {
/**
* 生成二維碼(帶內嵌的logo)
* 加密:將文字其他東西放在圖片里面
* 解密:反之
*/
//1.此處要根據用戶id+產品類型海報+ 命名圖片名稱
//2.圖片存在哪里呢?
// String imagePath = "src/main/resources/webapp1.jpg";
// String logo = "src/main/resources/smartLogo.png";
// String content = "https://blog.csdn.net/q15102780705/article/details/100060137";
// // String content = "https://www.baidu.com.cn";
// ZXingUtil.encodeimage(imagePath, "JPEG", content, 100, 100 , logo);
int width = 100;
int height = 100;
String url = "https://www.baidu.com.cn?誰是世界上最美的人";
String imagePath="src/main/resources/imagePath.png";
String beijingPath="src/main/resources/beijing.png";
String finalImagePath="src/main/resources/finalImagePath.png";
String format="png";
/**
* 1.生成二維碼 (不帶logo)
* 2. 合並圖片 二維碼圖片和海報圖片
*/
// 傳參:二維碼內容和生成路徑
if (ZXingUtil.orCode(url, imagePath, width, height,format)) {
System.out.println("ok,成功");
BufferedImage image=ZXingUtil.compositePicature(beijingPath, imagePath, finalImagePath, format);
} else {
System.out.println("no,失敗");
}
/**
* 解密 -->將二維碼內部的文字顯示出來
*/
// ZXingUtil.decodeImage(new File(imagePath));
}
}
Java畫圖 給圖片底部添加文字標題
import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; /** * JAVA 畫圖(生成文字水印) * * @author 傑寶寶 * */ public class ImageUtil { /** * @param str * 生產的圖片文字 * @param oldPath * 原圖片保存路徑 * @param newPath * 新圖片保存路徑 * @param width * 定義生成圖片寬度 * @param height * 定義生成圖片高度 * @return * @throws IOException */ public void create(String str, String oldPath, String newPath, int width, int height){ try { File oldFile = new File(oldPath); Image image = ImageIO.read(oldFile); File file = new File(newPath); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = bi.createGraphics(); g2.setBackground(Color.WHITE); g2.clearRect(0, 0, width, height); g2.drawImage(image, 0, 0, width - 25, height - 25, null); //這里減去25是為了防止字和圖重合 /** 設置生成圖片的文字樣式 * */ Font font = new Font("黑體", Font.BOLD, 25); g2.setFont(font); g2.setPaint(Color.BLACK); /** 設置字體在圖片中的位置 在這里是居中* */ FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = font.getStringBounds(str, context); double x = (width - bounds.getWidth()) / 2; //double y = (height - bounds.getHeight()) / 2; //Y軸居中 double y = (height - bounds.getHeight()); double ascent = -bounds.getY(); double baseY = y + ascent; /** 防止生成的文字帶有鋸齒 * */ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); /** 在圖片上生成文字 * */ g2.drawString(str, (int) x, (int) baseY); ImageIO.write(bi, "jpg", file); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) 