当前位置: 首页 > news >正文

Java自定义生成二维码(兼容你所有的需求)

1、概述

作为Java开发人员,说到生成二维码就会想到zxing开源二维码图像处理库,不可否认的是zxing确实很强大,但是实际需求中会遇到各种各样的需求是zxing满足不了的,于是就有了想法自己扩展zxing满足历史遇到的各种需求,经过3周的研究学习+开发,兼容你所有需求的Java二维码生成器孕育而生,接下来我们就看看我写的这个二维码生成器都实现了哪些功能。

2、已实现需求

  • zxing支持的二维码设置

  • 自定义logo,自动增加白边框、圆形、圆角矩形

  • 最终二维码圆角矩形生成

  • 自定义背景颜色

  • 自定义背景图片,可以设置二维码放置背景图片的位置

  • 自定义设置二维码顶部注释,自定义字体、字体颜色、背景颜色,居中、自动换行

  • 自定义设置二维码底部注释,自定义字体、字体颜色、背景颜色,居中、自动换行

  • 设置码点颜色、形状(普通、原型、方形、三角形、圆角矩形、菱形)

  • 设置码眼外框颜色、形状(方形、圆形-粗边、圆形-细边、圆角矩形-粗边、圆角矩形-中边、圆角矩形-细边)

  • 设置码眼内颜色、形状(方形、圆形、圆角矩形、三角形、菱形)

  • 其他继续扩展中

3、项目配置详细说明

3.1、二维码背景配置

package com.faea.qrcode.config;import lombok.Getter;import java.awt.*;/*** 二维码背景配置** @author liuchao* @date 2023/2/17*/
@Getter
public class CodeBackgroundConfig {public CodeBackgroundConfig() {this.color = Color.WHITE;}/*** 背景色,默认白色*/public Color color;/*** 二维码绘制在背景图上的X轴*/public int codeDrawX;/*** 二维码绘制在北京图上的Y轴*/public int codeDrawY;/*** 背景图片*/private Image image;public CodeBackgroundConfig color(Color color) {this.color = color;return this;}public CodeBackgroundConfig image(Image image) {this.image = image;return this;}public CodeBackgroundConfig codeDrawX(Integer codeDrawX) {this.codeDrawX = codeDrawX;return this;}public CodeBackgroundConfig codeDrawY(Integer codeDrawY) {this.codeDrawY = codeDrawY;return this;}
}

3.2、二维码码点配置

package com.faea.qrcode.config;import com.faea.qrcode.constants.CodeDotShapeEnum;
import lombok.Getter;import java.awt.*;/*** 二维码码点配置** @author liuchao* @date 2023/2/17*/
@Getter
public class CodeDotConfig {public CodeDotConfig() {this.color = Color.BLACK;this.shape = CodeDotShapeEnum.NORMAL;}/*** 码点颜色*/private Color color;/*** 形状枚举*/private CodeDotShapeEnum shape;public CodeDotConfig shape(CodeDotShapeEnum shape) {this.shape = shape;return this;}public CodeDotConfig color(Color color) {this.color = color;return this;}
}

3.3、二维码码眼内配置

package com.faea.qrcode.config;import com.faea.qrcode.constants.CodeEyeInsideShapeEnum;
import lombok.Getter;import java.awt.*;/*** 二维码码眼内配置** @author liuchao* @date 2023/2/19*/
@Getter
public class CodeEyeInsideConfig {public CodeEyeInsideConfig() {this(Color.BLACK, CodeEyeInsideShapeEnum.SQUARE);}public CodeEyeInsideConfig(Color color, CodeEyeInsideShapeEnum shape) {this.color = color;this.shape = shape;}/*** 颜色*/private Color color;/*** 形状*/private CodeEyeInsideShapeEnum shape;public CodeEyeInsideConfig color(Color color) {this.color = color;return this;}public CodeEyeInsideConfig shape(CodeEyeInsideShapeEnum shape) {this.shape = shape;return this;}
}

3.4、二维码码眼外配置

package com.faea.qrcode.config;import com.faea.qrcode.constants.CodeEyeOutShapeEnum;
import lombok.Getter;import java.awt.*;/*** 二维码码眼外配置** @author liuchao* @date 2023/2/19*/
@Getter
public class CodeEyeOutConfig {public CodeEyeOutConfig() {this(Color.BLACK, CodeEyeOutShapeEnum.SQUARE);}public CodeEyeOutConfig(Color color, CodeEyeOutShapeEnum shape) {this.color = color;this.shape = shape;}/*** 颜色*/private Color color;/*** 形状*/private CodeEyeOutShapeEnum shape;public CodeEyeOutConfig color(Color color) {this.color = color;return this;}public CodeEyeOutConfig shape(CodeEyeOutShapeEnum shape) {this.shape = shape;return this;}
}

3.5、二维码LOGO配置

package com.faea.qrcode.config;
import com.faea.qrcode.constants.CodeLogoShapeEnum;
import lombok.Data;import java.awt.*;
import java.io.File;/*** 二维码LOGO配置** @author liuchao* @date 2023/2/17*/
@Data
public class CodeLogoConfig {public CodeLogoConfig() {this(null);}public CodeLogoConfig(Image image) {this.image = image;this.scale = 0.1F;this.shape = CodeLogoShapeEnum.ROUNDED;this.alpha = 1F;}/*** LOGO 图片*/private Image image;/*** 形状*/private CodeLogoShapeEnum shape;/*** LOGO 透明度*/private Float alpha;/*** 缩放比例。比例大于1时为放大,小于1大于0为缩小*/private float scale;/*** 设置二维码中的Logo文件** @param logoPath 二维码中的Logo路径* @return this;*/public CodeLogoConfig image(String logoPath) {return image(FileUtil.file(logoPath));}/*** 设置二维码中的Logo文件** @param logoFile 二维码中的Logo* @return this;*/public CodeLogoConfig image(File logoFile) {return image(ImgUtil.read(logoFile));}/*** 设置二维码中的Logo** @param image 二维码中的Logo* @return this;*/public CodeLogoConfig image(Image image) {this.image = image;return this;}public CodeLogoConfig shape(CodeLogoShapeEnum shape) {this.shape = shape;return this;}public CodeLogoConfig alpha(Float alpha) {this.alpha = alpha;return this;}public CodeLogoConfig scale(float scale) {this.scale = scale;return this;}
}

3.6、二维码注释配置

package com.faea.qrcode.config;import lombok.Data;import java.awt.*;/*** 二维码注释配置** @author liuchao* @date 2023/2/17*/
@Data
public class CodeNoteConfig {public CodeNoteConfig() {this.rowSpacing = 5;this.size = 14;this.font = "SimHei";this.backColor = Color.DARK_GRAY;this.fontColor = Color.BLACK;}/*** 注释内容*/private String content;/*** 注释字体*/private String font;/*** 字体大小*/private Integer size;/*** 背景颜色*/private Color backColor;/*** 字体颜色*/private Color fontColor;/*** 行间距*/private Integer rowSpacing;public CodeNoteConfig backColor(Color color) {this.backColor = color;return this;}public CodeNoteConfig fontColor(Color color) {this.fontColor = color;return this;}public CodeNoteConfig content(String content) {this.content = content;return this;}public CodeNoteConfig font(String font) {this.font = font;return this;}public CodeNoteConfig size(Integer size) {this.size = size;return this;}public CodeNoteConfig rowSpacing(Integer rowSpacing) {this.rowSpacing = rowSpacing;return this;}
}

3.7、总配置入口类

package com.faea.qrcode.config;import cn.hutool.core.util.CharsetUtil;
import com.google.zxing.EncodeHintType;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.Getter;import java.nio.charset.Charset;
import java.util.HashMap;/*** 二维码总配置** @author liuchao* @date 2023/2/17*/
@Getter
public class CodeConfig {/*** 创建QrConfig** @return QrConfig* @since 4.1.14*/public static CodeConfig create() {return new CodeConfig();}/*** 构造,默认长宽为300*/public CodeConfig() {this(500, 500);}/*** 构造** @param width  宽* @param height 长*/public CodeConfig(int width, int height) {this.width = width;this.height = height;this.margin = 1;this.dot = new CodeDotConfig();this.background = new CodeBackgroundConfig();this.eyeOut = new CodeEyeOutConfig();this.eyeInside = new CodeEyeInsideConfig();this.errorCorrection = ErrorCorrectionLevel.H;this.charset = CharsetUtil.CHARSET_UTF_8;this.arc = 1D;}/*** 宽*/private Integer width;/*** 长*/private Integer height;/*** 边距1~4* 二维码空白区域,最小为0也有白边,只是很小,最小是6像素左右*/private Integer margin;/*** 码眼外*/private CodeEyeOutConfig eyeOut;/*** 码眼内*/private CodeEyeInsideConfig eyeInside;/*** 纠错级别*/private ErrorCorrectionLevel errorCorrection;/*** 编码*/private Charset charset;/*** 前景色配置*/private CodeDotConfig dot;/*** 背景色配置*/private CodeBackgroundConfig background;/*** 圆角弧度,0~1,为长宽占比* 设置最终二维码 圆角弧度* 1:原图* 0.3D:圆角矩形*/private Double arc;/*** logo*/private CodeLogoConfig logo;/*** 顶部注释*/private CodeNoteConfig topNote;/*** 底部注释*/private CodeNoteConfig bottomNote;public CodeConfig logo(CodeLogoConfig logo) {this.logo = logo;return this;}/*** 转换为Zxing的二维码配置** @return 配置*/public HashMap<EncodeHintType, Object> toHints() {// 配置final HashMap<EncodeHintType, Object> hints = new HashMap<>();if (null != this.charset) {hints.put(EncodeHintType.CHARACTER_SET, charset.toString().toLowerCase());}if (null != this.errorCorrection) {hints.put(EncodeHintType.ERROR_CORRECTION, this.errorCorrection);}if (null != this.margin) {hints.put(EncodeHintType.MARGIN, this.margin);}return hints;}public CodeConfig width(Integer width) {this.width = width;return this;}public CodeConfig height(Integer height) {this.height = height;return this;}public CodeConfig margin(Integer margin) {this.margin = margin;return this;}public CodeConfig eyeOut(CodeEyeOutConfig eyeOut) {this.eyeOut = eyeOut;return this;}public CodeConfig eyeInside(CodeEyeInsideConfig eyeInside) {this.eyeInside = eyeInside;return this;}public CodeConfig errorCorrection(ErrorCorrectionLevel errorCorrection) {this.errorCorrection = errorCorrection;return this;}public CodeConfig charset(Charset charset) {this.charset = charset;return this;}public CodeConfig dot(CodeDotConfig dot) {this.dot = dot;return this;}public CodeConfig background(CodeBackgroundConfig background) {this.background = background;return this;}public CodeConfig topNote(CodeNoteConfig topNote) {this.topNote = topNote;return this;}public CodeConfig bottomNote(CodeNoteConfig bottomNote) {this.bottomNote = bottomNote;return this;}public CodeConfig arc(Double arc) {this.arc = arc;return this;}
}

3.8、核心工具类

package com.faea.qrcode.util;import com.faea.qrcode.config.*;
import com.faea.qrcode.constants.CodeEyePositionEnum;
import com.faea.qrcode.constants.CodeLogoShapeEnum;
import com.faea.qrcode.model.CodeDotDrawModel;
import com.faea.qrcode.model.CodeEyeInsideDrawModel;
import com.faea.qrcode.model.CodeEyeOutDrawModel;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import lombok.Data;
import lombok.extern.java.Log;import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;/*** 二维码工具类** @author liuchao* @date 2023/2/17*/
@Log
public class CodeUtil {/*** 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示** @param content    内容* @param config     二维码配置,包括长、宽、边距、颜色等* @param imageType  图片类型(图片扩展名),见{@link ImgUtil}* @param logoBase64 logo 图片的 base64 编码* @return 图片 Base64 编码字符串*/public static String generateAsBase64(String content, CodeConfig config, String imageType, String logoBase64) {return generateAsBase64(content, config, imageType, Base64.decode(logoBase64));}/*** 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示** @param content   内容* @param config    二维码配置,包括长、宽、边距、颜色等* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}* @param logo      logo 图片的byte[]* @return 图片 Base64 编码字符串*/public static String generateAsBase64(String content, CodeConfig config, String imageType, byte[] logo) {return generateAsBase64(content, config, imageType, ImgUtil.toImage(logo));}/*** 生成代 logo 图片的 Base64 编码格式的二维码,以 String 形式表示** @param content   内容* @param config    二维码配置,包括长、宽、边距、颜色等* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}* @param logo      logo 图片的byte[]* @return 图片 Base64 编码字符串*/public static String generateAsBase64(String content, CodeConfig config, String imageType, Image logo) {config.getLogo().image(logo);return generateAsBase64(content, config, imageType);}/*** 生成 Base64 编码格式的二维码,以 String 形式表示** <p>* 输出格式为: data:image/[type];base64,[data]* </p>** @param content   内容* @param config    二维码配置,包括长、宽、边距、颜色等* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}* @return 图片 Base64 编码字符串*/public static String generateAsBase64(String content, CodeConfig config, String imageType) {final BufferedImage img = generate(content, config);return ImgUtil.toBase64DateUri(img, imageType);}/*** 生成PNG格式的二维码图片,以byte[]形式表示** @param content 内容* @param width   宽度* @param height  高度* @return 图片的byte[]*/public static byte[] generatePng(String content, int width, int height) {final ByteArrayOutputStream out = new ByteArrayOutputStream();generate(content, width, height, ImgUtil.IMAGE_TYPE_PNG, out);return out.toByteArray();}/*** 生成PNG格式的二维码图片,以byte[]形式表示** @param content 内容* @param config  二维码配置,包括长、宽、边距、颜色等* @return 图片的byte[]*/public static byte[] generatePng(String content, CodeConfig config) {final ByteArrayOutputStream out = new ByteArrayOutputStream();generate(content, config, ImgUtil.IMAGE_TYPE_PNG, out);return out.toByteArray();}/*** 生成二维码到文件,二维码图片格式取决于文件的扩展名** @param content    文本内容* @param width      宽度* @param height     高度* @param targetFile 目标文件,扩展名决定输出格式* @return 目标文件*/public static File generate(String content, int width, int height, File targetFile) {final BufferedImage image = generate(content, width, height);ImgUtil.write(image, targetFile);return targetFile;}/*** 生成二维码到文件,二维码图片格式取决于文件的扩展名** @param content    文本内容* @param width      宽度* @param height     高度* @param logo       logo图片* @param targetFile 目标文件,扩展名决定输出格式* @return 目标文件*/public static File generate(String content, int width, int height, Image logo, File targetFile) {CodeConfig config = new CodeConfig(width, height).logo(new CodeLogoConfig(logo));final BufferedImage image = generate(content, config);ImgUtil.write(image, targetFile);return targetFile;}/*** 生成二维码到输出流** @param content   文本内容* @param width     宽度* @param height    高度* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}* @param out       目标流*/public static void generate(String content, int width, int height, String imageType, OutputStream out) {final BufferedImage image = generate(content, width, height);ImgUtil.write(image, imageType, out);}/*** 生成二维码到输出流** @param content   文本内容* @param config    二维码配置,包括长、宽、边距、颜色等* @param imageType 图片类型(图片扩展名),见{@link ImgUtil}* @param out       目标流*/public static void generate(String content, CodeConfig config, String imageType, OutputStream out) {final BufferedImage image = generate(content, config);ImgUtil.write(image, imageType, out);}/*** 生成二维码图片** @param content 文本内容* @param width   宽度* @param height  高度* @return 二维码图片(黑白)*/public static BufferedImage generate(String content, int width, int height) {return generate(content, new CodeConfig(width, height));}/*** 生成二维码到文件,二维码图片格式取决于文件的扩展名** @param content    文本内容* @param config     二维码配置,包括长、宽、边距、颜色等* @param targetFile 目标文件,扩展名决定输出格式* @return 目标文件*/public static File generate(String content, CodeConfig config, File targetFile) {final BufferedImage image = generate(content, config);ImgUtil.write(image, targetFile);return targetFile;}/*** 生成二维码图片** @param content 二维码内容* @param config  二维码配置* @return java.awt.image.BufferedImage* @author liuchao* @date 2023/2/17*/public static BufferedImage generate(String content, CodeConfig config) {BitMatrix bitMatrix;try {bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE,config.getWidth(), config.getHeight(), config.toHints());} catch (WriterException e) {throw new RuntimeException(e);}//获取二维码图片尺寸信息CodeImageSizeInfo sizeInfo = convertCodeImageSizeInfo(config);BufferedImage image = toImage(bitMatrix, sizeInfo, config);//绘制背景图片image = drawBackgroundImage(image, config, sizeInfo);//绘制logodrawLogo(image, config);//圆角处理if (config.getArc() < 1D) {image = ImgUtil.toBufferedImage(Img.from(image).round(config.getArc()).getImg());}return image;}/*** 通过内容配置转换为字体** @param note* @return java.awt.FontMetrics* @author liuchao* @date 2023/2/17*/private static FontMetrics convertFont(CodeNoteConfig note) {if (null == note) {return null;}Font font = new Font(note.getFont(), Font.PLAIN, note.getSize());JLabel jLabel = new JLabel(note.getContent());//第一次获取非常慢,建议在应用启动的时候加载一次FontMetrics fontMetrics = jLabel.getFontMetrics(font);return fontMetrics;}/*** BitMatrix转BufferedImage** @param matrix   BitMatrix* @param sizeInfo 二维码尺寸信息* @param config* @return java.awt.image.BufferedImage* @author liuchao* @date 2023/2/17*/private static BufferedImage toImage(BitMatrix matrix, CodeImageSizeInfo sizeInfo, CodeConfig config) {final int width = matrix.getWidth();//创建二维码最终ImageBufferedImage image = new BufferedImage(width, sizeInfo.getCodeImageTotalHeight(), BufferedImage.TYPE_INT_ARGB);Graphics2D graphics2D = ImageUtil.imageToGraphics2D(image);//绘制背景drawBackgroundColor(graphics2D, sizeInfo, config, matrix);// 处理上、下注释、码点、码眼drawNoteAndDotEye(graphics2D, sizeInfo, config, matrix);//添加注释drawNote(graphics2D, sizeInfo, config);graphics2D.dispose();image.flush();return image;}/*** 绘制logo** @param image* @param config* @return void* @author liuchao* @date 2023/2/18*/private static void drawLogo(BufferedImage image, CodeConfig config) {if (null == config.getLogo() || null == config.getLogo().getImage()) {return;}CodeLogoConfig logoConfig = config.getLogo();//圆角弧度,0~1,为长宽占比Double arc = logoConfig.getShape().getArc();//缩放BufferedImage srcImage = ImgUtil.toBufferedImage(Img.from(logoConfig.getImage()).scale(logoConfig.getScale()).round(arc).getImg());//增加边框 非原型 则增加边框if (!logoConfig.getShape().equals(CodeLogoShapeEnum.ORIGINAL)) {srcImage = ImageUtil.roundBorder(srcImage, arc);}ImgUtil.pressImage(image, srcImage, new Rectangle(srcImage.getWidth(), srcImage.getHeight()), logoConfig.getAlpha());}/*** 增加注释** @param graphics2D* @param sizeInfo* @param config* @return void* @author liuchao* @date 2023/2/18*/private static void drawNote(Graphics2D graphics2D, CodeImageSizeInfo sizeInfo, CodeConfig config) {if (sizeInfo.getTopNoteHeight() == 0 && sizeInfo.getBottomNoteHeight() == 0) {return;}int startWriteY = 0;//顶部注释if (sizeInfo.getTopNoteHeight() > 0) {CodeNoteConfig topNode = config.getTopNote();drawHorizontalWords(graphics2D, startWriteY, topNode.getContent(), sizeInfo.topNoteFontMetrics, topNode.getFontColor(),config.getWidth(), sizeInfo.getTopNoteRowSize(),topNode.getRowSpacing());startWriteY += sizeInfo.getTopNoteHeight();}//底部注释if (sizeInfo.getBottomNoteHeight() > 0) {startWriteY += config.getHeight();CodeNoteConfig bottomNote = config.getBottomNote();drawHorizontalWords(graphics2D, startWriteY, bottomNote.getContent(), sizeInfo.bottomNoteFontMetrics, bottomNote.getFontColor(),config.getWidth(), sizeInfo.getTopNoteRowSize(),bottomNote.getRowSpacing());}}/*** 在Graphics2D 写横向文字** @param graphics2D* @param startWriteY* @param content* @param fontMetrics* @param fontColor   字体颜色* @param qrCodeWidth* @param rowSize* @param rowSpacing* @return void* @author liuchao* @date 2023/2/18*/private static void drawHorizontalWords(Graphics2D graphics2D, int startWriteY, String content,FontMetrics fontMetrics, Color fontColor, int qrCodeWidth,int rowSize, int rowSpacing) {graphics2D.setFont(fontMetrics.getFont());graphics2D.setColor(fontColor);int rowHeight = fontMetrics.getHeight();//当前写入Y轴int curWriteY = startWriteY + rowHeight;if (rowSize > 1) {//当前行字符StringBuffer curRowWords = new StringBuffer();for (int i = 0; i < content.length(); i++) {curRowWords.append(content.charAt(i));if (i == (content.length() - 1)) {int wordWidth = fontMetrics.stringWidth(curRowWords.toString());int writeX = (qrCodeWidth - wordWidth) / 2;graphics2D.drawString(curRowWords.toString(), writeX, curWriteY);} else {//判断当前已累加字符+下一个字符  长度是否大于 总宽度StringBuffer tempWords = new StringBuffer(curRowWords).append(content.charAt(i + 1));if (fontMetrics.stringWidth(tempWords.toString()) > qrCodeWidth) {int wordWidth = fontMetrics.stringWidth(curRowWords.toString());int writeX = (qrCodeWidth - wordWidth) / 2;graphics2D.drawString(curRowWords.toString(), writeX, curWriteY);curWriteY += rowHeight + rowSpacing;curRowWords.delete(0, curRowWords.length());//最后一个字符了}}}} else {int wordWidth = fontMetrics.stringWidth(content);int writeX = (qrCodeWidth - wordWidth) / 2;graphics2D.drawString(content, writeX, curWriteY);}}/*** 绘制注释+码点+码眼** @param graphics2D* @param sizeInfo* @param config* @param matrix* @return void* @author liuchao* @date 2023/2/22*/private static void drawNoteAndDotEye(Graphics2D graphics2D,CodeImageSizeInfo sizeInfo, CodeConfig config, BitMatrix matrix) {CodeDotConfig dot = config.getDot();final int height = matrix.getHeight();final int width = matrix.getWidth();Boolean leftTopOut = false;Boolean rightTopOut = false;Boolean leftBottomOut = false;Boolean leftTopInside = false;Boolean rightTopInside = false;Boolean leftBottomInside = false;//上注释if (sizeInfo.getTopNoteHeight() > 0) {CodeNoteConfig topNote = config.getTopNote();graphics2D.setColor(topNote.getBackColor());graphics2D.fillRect(0, 0, width, sizeInfo.getTopNoteHeight());}//下注释if (sizeInfo.getBottomNoteHeight() > 0) {CodeNoteConfig bottomNote = config.getBottomNote();graphics2D.setColor(bottomNote.getBackColor());graphics2D.fillRect(0, sizeInfo.getTopNoteHeight() + height, width, sizeInfo.getBottomNoteHeight());}int multiple = matrix.getMultiple();int leftPadding = matrix.getLeftPadding();int topPadding = matrix.getTopPadding();ByteMatrix input = matrix.getInputMatrix();for (int inputY = 0, outputY = topPadding; inputY < input.getHeight(); inputY++, outputY += multiple) {// Write the contents of this row of the barcodefor (int inputX = 0, outputX = leftPadding; inputX < input.getWidth(); inputX++, outputX += multiple) {if (input.get(inputX, inputY) == 1) {int y = outputY + sizeInfo.getTopNoteHeight();// 左上角码眼,外边框if (input.getEyeOutPoint(CodeEyePositionEnum.LEFT_TOP, inputX, inputY) == 1) {if (!leftTopOut) {config.getEyeOut().getShape().draw(graphics2D, CodeEyeOutDrawModel.create(config.getEyeOut().getColor(), outputX, y, multiple));leftTopOut = true;}//右上角码眼,外边框} else if (input.getEyeOutPoint(CodeEyePositionEnum.RIGHT_TOP, inputX, inputY) == 1) {if (!rightTopOut) {config.getEyeOut().getShape().draw(graphics2D, CodeEyeOutDrawModel.create(config.getEyeOut().getColor(), outputX, y, multiple));rightTopOut = true;}//左下角码眼,外边框} else if (input.getEyeOutPoint(CodeEyePositionEnum.LEFT_BOTTOM, inputX, inputY) == 1) {if (!leftBottomOut) {config.getEyeOut().getShape().draw(graphics2D, CodeEyeOutDrawModel.create(config.getEyeOut().getColor(), outputX, y, multiple));leftBottomOut = true;}// 左上角码眼,内边框} else if (input.getEyeInsidePoint(CodeEyePositionEnum.LEFT_TOP, inputX, inputY) == 1) {if (!leftTopInside) {config.getEyeInside().getShape().draw(graphics2D, CodeEyeInsideDrawModel.create(config.getEyeInside().getColor(), outputX, y, multiple));leftTopInside = true;}// 右上角码眼,内边框} else if (input.getEyeInsidePoint(CodeEyePositionEnum.RIGHT_TOP, inputX, inputY) == 1) {if (!rightTopInside) {config.getEyeInside().getShape().draw(graphics2D, CodeEyeInsideDrawModel.create(config.getEyeInside().getColor(), outputX, y, multiple));rightTopInside = true;}// 左下角码眼,内边框} else if (input.getEyeInsidePoint(CodeEyePositionEnum.LEFT_BOTTOM, inputX, inputY) == 1) {if (!leftBottomInside) {config.getEyeInside().getShape().draw(graphics2D, CodeEyeInsideDrawModel.create(config.getEyeInside().getColor(), outputX, y, multiple));leftBottomInside = true;}} else {// 其他黑色区域dot.getShape().draw(graphics2D, new CodeDotDrawModel(dot.getColor(), outputX, y, multiple, multiple));}}}}}/*** 绘制背景图片** @param codeImage* @param config* @param sizeInfo  尺寸信息* @return java.awt.image.BufferedImage* @author liuchao* @date 2023/2/22*/private static BufferedImage drawBackgroundImage(BufferedImage codeImage, CodeConfig config, CodeImageSizeInfo sizeInfo) {CodeBackgroundConfig background = config.getBackground();if (ObjectUtil.isEmpty(background.getImage())) {return codeImage;}final int codeWidth = codeImage.getWidth();final int codeHeight = codeImage.getHeight();BufferedImage backgroundImage = ImgUtil.toBufferedImage(background.getImage());int imageW = backgroundImage.getWidth(null);int imageH = backgroundImage.getHeight(null);//背景图的宽高不能小于  二维码宽高int w = imageW < config.getWidth() ? config.getWidth() : imageW;int h = imageH < config.getHeight() ? config.getHeight() : imageH;//如果绘制X\Y都等于0,则直接填充if (background.getCodeDrawX() == 0 && background.getCodeDrawY() == 0) {w = config.getWidth();h = config.getHeight() + sizeInfo.getTopNoteHeight() + sizeInfo.getBottomNoteHeight();}// 背景图缩放if (imageW != w || imageH != h) {BufferedImage newBackgroundImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);newBackgroundImage.getGraphics().drawImage(backgroundImage.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, null);backgroundImage = newBackgroundImage;}Graphics2D graphics2D = ImageUtil.imageToGraphics2D(backgroundImage);int codeDrawX = (w - codeWidth) >> 1;int codeDrawY = (h - codeHeight) >> 1;//如果设置了开始绘制的坐标,则按照这个坐标绘制if (background.getCodeDrawX() != 0 || background.getCodeDrawY() != 0) {codeDrawX = background.getCodeDrawX();codeDrawY = background.getCodeDrawY();}graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1F));graphics2D.drawImage(codeImage.getScaledInstance(codeWidth, codeHeight, Image.SCALE_SMOOTH), codeDrawX, codeDrawY,null);graphics2D.dispose();backgroundImage.flush();return backgroundImage;}/*** 绘制背景图片** @param graphics2D* @param sizeInfo   尺寸信息* @param config     配置信息* @return void* @author liuchao* @date 2023/2/21*/private static void drawBackgroundColor(Graphics2D graphics2D, CodeImageSizeInfo sizeInfo, CodeConfig config, BitMatrix matrix) {CodeBackgroundConfig background = config.getBackground();//如果设置了背景图片,则忽略背景色if (ObjectUtil.isNotEmpty(background.getImage())) {return;}//设置二维码区域背景颜色  全部为设置的背景色graphics2D.setColor(background.getColor());graphics2D.fillRect(0, sizeInfo.getTopNoteHeight(), matrix.getWidth(), matrix.getHeight());}/*** 转换二维码最终图片尺寸信息** @param config 二维码配置信息* @return com.faea.qrcode.util.CodeUtil.CodeImageSizeInfo* @author liuchao* @date 2023/2/18*/private static CodeImageSizeInfo convertCodeImageSizeInfo(CodeConfig config) {int qrCodeWidth = config.getWidth();int qrCodeHeight = config.getHeight();CodeImageSizeInfo info = new CodeImageSizeInfo();//二维码上注释Integer topNoteHeight = 0;CodeNoteConfig topNote = config.getTopNote();if (null != topNote) {FontMetrics topNoteFont = convertFont(topNote);int topNoteRowHeight = topNoteFont.getHeight();int topNoteWidth = topNoteFont.stringWidth(topNote.getContent());if (topNoteWidth > qrCodeWidth) {int topNoteRowSize = topNoteWidth / qrCodeWidth;if (topNoteWidth % qrCodeWidth != 0) {topNoteRowSize += 1;}info.setTopNoteRowSize(topNoteRowSize);topNoteHeight += (topNote.getRowSpacing() + topNoteRowHeight) * topNoteRowSize;} else {topNoteHeight += (topNote.getRowSpacing() + topNoteRowHeight);}info.setTopNoteHeight(topNoteHeight);info.setTopNoteFontMetrics(topNoteFont);}CodeNoteConfig bottomNote = config.getBottomNote();Integer bottomNoteHeight = 0;if (null != bottomNote) {//二维码下注释FontMetrics bottomNoteFont = convertFont(bottomNote);int bottomNoteRowHeight = bottomNoteFont.getHeight();int bottomNoteWidth = bottomNoteFont.stringWidth(bottomNote.getContent());if (bottomNoteWidth > qrCodeWidth) {int bottomNoteRowSize = bottomNoteWidth / qrCodeWidth;if (bottomNoteWidth % qrCodeWidth != 0) {bottomNoteRowSize += 1;}info.setBottomNoteRowSize(bottomNoteRowSize);bottomNoteHeight += (bottomNote.getRowSpacing() + bottomNoteRowHeight) * bottomNoteRowSize;} else {bottomNoteHeight += (bottomNote.getRowSpacing() + bottomNoteRowHeight);}info.setBottomNoteHeight(bottomNoteHeight);info.setBottomNoteFontMetrics(bottomNoteFont);}info.setCodeImageTotalHeight(topNoteHeight + qrCodeHeight + bottomNoteHeight);return info;}/*** 二维码尺寸信息** @author liuchao* @date 2023/2/18*/@Datastatic class CodeImageSizeInfo {/*** 顶部注释占用高度*/int topNoteHeight;/*** 顶部注释 字体信息*/FontMetrics topNoteFontMetrics;/*** 顶部注释占用行数*/int topNoteRowSize;/*** 底部注释占用高度*/int bottomNoteHeight;/*** 底部注释占用行数*/int bottomNoteRowSize;/*** 底部注释 字体信息*/FontMetrics bottomNoteFontMetrics;/*** 二维码图片总高度*/int codeImageTotalHeight;}}

4、效果查看

4.1、效果单元测试

总体写了14个单元测试,通过单元测试可以看出,使用起来还是很方便的。

package com.faea;import com.faea.qrcode.config.CodeConfig;
import com.faea.qrcode.config.CodeLogoConfig;
import com.faea.qrcode.config.CodeNoteConfig;
import com.faea.qrcode.constants.CodeDotShapeEnum;
import com.faea.qrcode.constants.CodeEyeInsideShapeEnum;
import com.faea.qrcode.constants.CodeEyeOutShapeEnum;
import com.faea.qrcode.constants.CodeLogoShapeEnum;
import com.faea.qrcode.util.CodeUtil;
import org.junit.Test;import java.awt.*;
import java.io.File;/*** 二维码测试** @author liuchao* @date 2023/2/23*/
public class CodeTest {/*** 保存二维码地址*/private static final String SAVE_FILE_PATH = "src/test/code/";/*** 二维码内容*/private static final String content = "https://blog.csdn.net/u011837804";/*** 注释*/private static final String note = "Java全栈行动派";/*** 普通二维码*/@Testpublic void test1() {CodeUtil.generate(content, 300, 300,new File(SAVE_FILE_PATH + "gen/test1.png"));}/*** 带logo*/@Testpublic void test2() {CodeUtil.generate(content, 300, 300,ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png")),new File(SAVE_FILE_PATH + "gen/test2.png"));}/*** 圆形logo*/@Testpublic void test3() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))).shape(CodeLogoShapeEnum.CIRCLE));CodeUtil.generate(content, config,new File(SAVE_FILE_PATH + "gen/test3.png"));}/*** 原型logo*/@Testpublic void test4() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))).shape(CodeLogoShapeEnum.ORIGINAL));CodeUtil.generate(content, config,new File(SAVE_FILE_PATH + "gen/test4.png"));}/*** 圆角二维码*/@Testpublic void test5() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png")))).arc(0.3D);CodeUtil.generate(content, config,new File(SAVE_FILE_PATH + "gen/test5.png"));}/*** 背景颜色*/@Testpublic void test6() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.getBackground().color(ImgUtil.getColor(129590));CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test6.png"));}/*** 设置背景图片*/@Testpublic void test7() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.getBackground().image(ImgUtil.read(new File(SAVE_FILE_PATH + "background.png")));CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test7.png"));}/*** 设置上注释*/@Testpublic void test8() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.topNote(new CodeNoteConfig().content(note).backColor(Color.WHITE));CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test8.png"));}/*** 设置上注释 + 背景颜色+ 字颜色*/@Testpublic void test9() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.topNote(new CodeNoteConfig().content(note).backColor(Color.WHITE));CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test9.png"));}/*** 设置下注释*/@Testpublic void test10() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.bottomNote(new CodeNoteConfig().content(note).backColor(Color.WHITE));CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test10.png"));}/*** 设置码点颜色*/@Testpublic void test11() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.bottomNote(new CodeNoteConfig().content(note).backColor(Color.WHITE).fontColor(Color.BLUE));config.getDot().color(Color.BLUE);CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test11.png"));}/*** 设置码眼颜色*/@Testpublic void test12() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.bottomNote(new CodeNoteConfig().content(note).backColor(Color.WHITE).fontColor(Color.BLUE));config.getDot().color(Color.BLUE);config.getEyeInside().color(Color.BLUE);config.getEyeOut().color(Color.RED);CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test12.png"));}/*** 设置码点形状*/@Testpublic void test13() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.bottomNote(new CodeNoteConfig().content(note).backColor(Color.WHITE).fontColor(Color.BLUE));config.getDot().color(Color.BLUE).shape(CodeDotShapeEnum.DIAMOND);config.getEyeInside().color(Color.BLUE);config.getEyeOut().color(Color.RED);CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test13.png"));}/*** 设置码眼形状*/@Testpublic void test14() {CodeConfig config = new CodeConfig(300, 300).logo(new CodeLogoConfig(ImgUtil.read(new File(SAVE_FILE_PATH + "logo.png"))));config.bottomNote(new CodeNoteConfig().content(note).backColor(Color.WHITE).fontColor(Color.BLUE));config.getDot().color(Color.BLUE).shape(CodeDotShapeEnum.TRIANGLE);config.getEyeInside().color(Color.BLUE).shape(CodeEyeInsideShapeEnum.ROUNDED);config.getEyeOut().color(Color.RED).shape(CodeEyeOutShapeEnum.ROUNDED_THICK_EDGE);CodeUtil.generate(content, config, new File(SAVE_FILE_PATH + "gen/test14.png"));}
}

4.2、生成所有的效果二维码

由于文章审核要求,所以做了图片模糊,但是二维码优化效果还是可以看清楚的。

不可否认的是要实现这些功能,需要对二维码生成原理、zxing源码等非常属性,着实让小编下了很大的功能,从上面小编贴出来的代码可以看出针对每个设置项注释是非常到位的,核心工具类也贴出来了,希望对朋友们的开发有帮助,全部源码下载地址:https://download.csdn.net/download/u011837804/87490526

相关文章:

Java自定义生成二维码(兼容你所有的需求)

1、概述作为Java开发人员&#xff0c;说到生成二维码就会想到zxing开源二维码图像处理库&#xff0c;不可否认的是zxing确实很强大&#xff0c;但是实际需求中会遇到各种各样的需求是zxing满足不了的&#xff0c;于是就有了想法自己扩展zxing满足历史遇到的各种需求&#xff0c…...

Spring事务的隔离级别

事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题 事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题 事务的特性: 隔离性:多个事务在并发执行的时候&#xff0c;多个事务执行的一个行为模式&#xff0c;当一个事务执行的时候&#xff0c;另一个事务执行的一个行…...

JVM系统优化实践(4):以支付系统为例

您好&#xff0c;我是湘王&#xff0c;这是我的CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e;前面说过&#xff0c;JVM会将堆内存划分为年轻代、老年代两个区域。年轻代会将创建和使用完之后马上就要回收的对象放在里面&#xff0c;而老年代则将创建之后需要…...

16- TensorFlow实现线性回归和逻辑回归 (TensorFlow系列) (深度学习)

知识要点 线性回归要点: 生成线性数据: x np.linspace(0, 10, 20) np.random.rand(20)画点图: plt.scatter(x, y)TensorFlow定义变量: w tf.Variable(np.random.randn() * 0.02)tensor 转换为 numpy数组: b.numpy()定义优化器: optimizer tf.optimizers.SGD()定义损失: …...

无自动化测试系统设计方法论

灵活 敏捷 迭代。 自动化测试 辩思 测试必不可少 想想看没有充分测试的代码, 哪一次是一次过的? 哪一次不需要经历下测试的鞭挞? 不要以为软件代码容易改, 就对于质量不切实际的自信—那是自大! 不适用自动化测试的case 遗留系统。太多的依赖方, 不想用过多的mock > …...

架构初探-学习笔记

1 什么是架构 有关软件整体结构与组件的抽象描述&#xff0c;用于指导软件系统各个方面的设计。 1.1 单机架构 所有功能都实现在一个进程里&#xff0c;并部署在一台机器上。 1.2 单体架构 分布式部署单机架构 1.3 垂直应用架构 按应用垂直切分的单体架构 1.4 SOA架构 将…...

在成都想转行IT,选择什么专业比较好?

很多创新型的互联网服务公司的核心其实都是软件&#xff0c;创新的基础、运行的支撑都是软件。例如&#xff0c;软件应用到了出租车行业&#xff0c;就形成了巅覆行业的滴滴;软件应用到了金融领域&#xff0c;就形成互联网金融;软件运用到餐饮行业&#xff0c;就形成美团;软件运…...

【Spark分布式内存计算框架——Spark Streaming】4.入门案例(下)Streaming 工作原理

2.3 Streaming 工作原理 SparkStreaming处理流式数据时&#xff0c;按照时间间隔划分数据为微批次&#xff08;Micro-Batch&#xff09;&#xff0c;每批次数据当做RDD&#xff0c;再进行处理分析。 以上述词频统计WordCount程序为例&#xff0c;讲解Streaming工作原理。 创…...

2、算法先导---思维能力与工具

题目 碎纸片的拼接复原(2013B) 内容 破碎文件的拼接在司法物证复原、历史文献修复以及军事情报获取等领域都有着重要的应用。传统上&#xff0c;拼接复原工作需由人工完成&#xff0c;准确率较高&#xff0c;但效率很低。特别是当碎片数量巨大&#xff0c;人工拼接很难在短时…...

WordPress 函数:add_theme_support() 开启主题自定义功能(全面)

add_theme_support() 用于在我们的当前使用的主题添加一些特殊的功能&#xff0c;函数一般写在主题的functions.php文件中&#xff0c;当然也可以再插件中使用钩子来调用该函数&#xff0c;如果是挂在钩子上&#xff0c;那他必须挂在after_setup_theme钩子上&#xff0c;因为 i…...

Winform控件开发(16)——Timer(史上最全)

前言: Timer控件的作用是按用户定义的时间间隔引发事件的计时器,说的直白点就是,他就像一个定时炸弹一样到了一定时间就爆炸一次,区别在于定时炸弹炸完了就不会再次爆炸了,但是Timer这个计时器到了下一个固定时间还会触发一次,上面那张图片就是一个典型的计时器,该定时器…...

游戏高度可配置化:通用数据引擎(data-e)及其在模块化游戏开发中的应用构想图解

游戏高度可配置化&#xff1a;通数据引擎在模块化游戏开发中的应用构想图解 ygluu 码客 卢益贵 目录 一、前言 二、模块化与插件 1、常规模块化 2、插件式模块化&#xff08;插件开发&#xff09; 三、通用数据引擎理论与构成 1、名字系统&#xff08;数据类型&#xf…...

CountDownLatch与CyclicBarrier原理剖析

1.CountDownLatch 1.1 什么是CountDownLatch CountDownLatch是一个同步工具类&#xff0c;用来协调多个线程之间的同步&#xff0c;或者说起到线程之间的通信&#xff08;而不是用作互斥的作用&#xff09;。 CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之…...

NLP中的对话机器人——预训练基准模型

引言 本文是七月在线《NLP中的对话机器人》的视频笔记&#xff0c;主要介绍FAQ问答型聊天机器人的实现。 场景二 上篇文章中我们解决了给定一个问题和一些回答&#xff0c;从中找到最佳回答的任务。 在场景二中&#xff0c;我们来实现&#xff1a; 给定新问题&#xff0c;从…...

C语言学习及复习笔记-【14】C文件读写

14 C文件读写 14.1打开文件 您可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件&#xff0c;这个调用会初始化类型 FILE 的一个对象&#xff0c;类型 FILE包含了所有用来控制流的必要的信息。下面是这个函数调用的原型&#xff1a; FILE *fopen( const char…...

模拟退火算法优化灰色

clc; clear; close all; warning off; %% tic T01000; % 初始温度 Tend1e-3; % 终止温度 L200; % 各温度下的迭代次数&#xff08;链长&#xff09; q0.9; %降温速率 X[16.4700 96.1000 16.4700 94.4400 20.0900 92.5400 22.3900 93.3700 25.…...

Pandas怎么添加数据列删除列

Pandas怎么添加数据列 1、直接赋值 # 1、直接赋值df.loc[:, "最高气温"] df["最高气温"].str.replace("℃", "").astype("int32")df.loc[:, "最低气温"] df["最低气温"].str.replace("℃"…...

C++类和对象:构造函数和析构函数

目录 一. 类的六个默认成员函数 二. 构造函数 2.1 什么是构造函数 2.2 编译器自动生成的默认构造函数 2.3 构造函数的特性总结 三. 析构函数 3.1 什么是析构函数 3.2 编译器自动生成的析构函数 3.3 析构函数的特性总结 一. 类的六个默认成员函数 对于任意一个C类&…...

【Stata】从入门到精通.零基础小白必学的教程,一学就fei

视频教程移步&#xff1a;https://www.bilibili.com/video/BV1hK4y1d714/?p4&spm_id_frompageDriver&vd_sourcecc8074e9c81a225f214226065db53d32P3 第二讲 Stata处理数据全流程&#xff08;上&#xff09; P3 - 01:37&#xfeff;内置数据 file example datasets使用…...

【RuoYi优化】调整JVM启动内存

📔 笔记介绍 大家好,千寻简笔记是一套全部开源的企业开发问题记录,毫无保留给个人及企业免费使用,我是作者星辰,笔记内容整理并发布,内容有误请指出,笔记源码已开源,前往Gitee搜索《chihiro-notes》,感谢您的阅读和关注。 作者各大平台直链: GitHub | Gitee | CSD…...

[架构模型]MVC模型详细介绍,并应用到unity中

简介&#xff1a; MVC模式是一种软件架构模式&#xff0c;它将应用程序分为三个主要部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&#xff09;。MVC模式的目标是实现应用程序的松耦合&#xff0c;以便…...

?? JavaScript 双问号(空值合并运算符)

?? JavaScript 双问号&#xff08;空值合并运算符) 一、简述 在网上浏览 JavaScript 代码时或者学习其他代码时&#xff0c;可能会发现有的表达式用了两个问号&#xff08;??&#xff09;如下所示&#xff1a; let username; console.log(username ?? "Guest"…...

作业2.25----通过操作Cortex-A7核,串口输入相应的命令,控制LED灯进行工作

1.通过操作Cortex-A7核&#xff0c;串口输入相应的命令&#xff0c;控制LED灯进行工作 例如在串口输入led1on,开饭led1灯点亮 2.例如在串口输入led1off,开饭led1灯熄灭 3.例如在串口输入led2on,开饭led2灯点亮 4.例如在串口输入led2off,开饭led2灯熄灭 5.例如在串口输入led…...

0101基础概念-图-数据结构和算法(Java)

文章目录1 图1.1 定义1.2 4种图模型2 无向图2.1 定义2.2 术语后记1 图 1.1 定义 图是一种非线性的数据结构&#xff0c;表示多对多的关系。 图&#xff08;Graph&#xff09;是由顶点的有穷非空集合和顶点之间边的集合组成&#xff0c;通常表示为&#xff1a;G(V, E)&#xf…...

Linux基础命令和工具使用详解

Linux基础命令和工具使用详解一、grep搜索字符二、find查找文件三、ls 显示文件四、wc命令计算字数五、uptime机器启动时间负载六、ulimit用户资源七、curl http八、scp远程拷贝九、dos2unix和unix2dos十、sed 行处理10.1、简单模式10.2、替换模式十一、awk 列处理11.1、打印某…...

一个好的python文件可以有几种用途?

大家好鸭&#xff01;我是小熊猫~ 这次来带大家浅浅回顾一点python小知识~ 源码资料电子书:点击此处跳转文末名片获取 python文件总共有两种用途&#xff1a; 一种是执行文件另一种是被当做模块导入 编写好的一个python文件可以有两种用途&#xff1a; 1. 脚本&#xff0c;…...

HDFS优化

单节点多块磁盘数据均衡 生成HDFS块均衡计划 hdfs diskbalancer -plan node1 执行均衡计划,node1.plan.json均衡计划文件 hdfs diskbalancer -execute node1.plan.json 查看当前均衡任务的执行情况 hdfs diskbalancer -query node1 取消均衡任务hdfs diskbalancer -cancel nod…...

行测-判断推理-图形推理-样式规律-黑白运算

黑白元素个数不同&#xff0c;优先考虑黑白运算白白白黑黑白黑白黑选A考试时&#xff0c;这种题不要先把规律全部推出来&#xff0c;再去做题&#xff0c;太慢了直接看要推的图&#xff0c;通过排除法选答案黑白元素个数不同&#xff0c;优先考虑黑白运算白白白黑黑白黑白黑选B…...

java+springboot+vue高校学生医疗保险管理系统

医保管理系统是对与职工健康息息相关的档案进行的系统化、自动化的管理&#xff0c;主要是对职工办理的医疗保险的管理&#xff0c;本系统能够很好的适应社会的需求&#xff0c;最大化的为城镇职工提供服务。医疗保险是国家社会保障体系的重要组成部分&#xff0c;也是社会保险…...

[已解决] AHK 映射 ESC 延迟 500 ms 的严重问题

问题描述 今天发现一个重大bug&#xff0c;我竟然用了一年多都不知道&#xff01; CapsLock::Esc 我的 ahk 脚本将 capslock 映射为 esc&#xff0c;但这在vim环境中&#xff0c;估算响应 500ms。 也就说按下 caps 键&#xff0c;还要等一会&#xff0c;才进入normal模式 如果…...

网站开发在哪里接活/公司个人怎么做网络推广

深圳职业技术学院2015年自主招生考试(面向中职毕业生)计算机应用技术专业考试大纲专业综合理论考试大纲《计算机基础》与《C语言程序设计基础》基本要求&#xff1a;了解计算机的发展与计算机的特点熟知计算机的基本结构与工作原理认识计算机中的信息表示与存储掌握Windows XP操…...

三门峡网站建设电话/360网站推广怎么做

初学者应该选择学习Python还是C语言 发布时间&#xff1a;2020-11-21 14:11:31 来源&#xff1a;亿速云 阅读&#xff1a;74 作者&#xff1a;小新 小编给大家分享一下初学者应该选择学习Python还是C语言&#xff0c;希望大家阅读完这篇文章后大所收获&#xff0c;下面让我们一…...

郑州网站建设公司 艾特/移动建站模板

办公室是企业办公的地方&#xff0c;对于企业而言&#xff0c;一个办公室的形象对于企业在团队精神、宣传展示时十分关键&#xff0c;对于整体实力协作、客户信赖的展示也是有一定的影响。人们在对办公空间合理、利润较大化利用的同时&#xff0c;如何打造一个时尚的办公空间设…...

南充网站设计/网站推广途径和要点

举例: 340%60 40 &#xff0c;怎么来的&#xff1f; 340 - 60*5 40 340 - (比340小的那个可以被60整除的正整数) . 40 如果是负数&#xff1a; -340%60 -340 - (比-340小的那个可以被60整除的负整数) -340 - (-360) 20 如图&#xff1a;也可以换个思路想&#xff0c; -340…...

云南 房地产网站建设/sem竞价开户

创建了超级管理员之后登录http://127.0.0.1:8000/admin/怎么都显示查不到url&#xff0c;查了很多网站也没找到原因&#xff0c;后来想起每次新建项目的时候都会有默认的一个url&#xff0c;而系统找不到admin页面的原因就是没有下面的路径 from django.contrib import admin …...

那个网站做稻草交易/搜狗收录提交入口

交换机stack 1。注意交换机型号,ios版本必须都保持一致。 2。连接好堆叠线 首先更改交换机的序号,更改后更改交换机的优先级 注意:新的交换机默认堆叠序列号(stack member number),堆叠优先级(stack member priority value)都为1。 如果新加一交换机需要做,改变当面堆…...