近期一直忙于开发微信商城项目,应客户要求,要开发个有图标的二维码。经过两次改版,终于实现了该功能(第一次没有小图标,这次才整合好的),如下是完整代码 。
该代码使用Java7开发,另外使用 core-2.2.jar jar[http://pan.baidu.com/s/1skTwHQ1] 包 。
1 package com.rick.common.utils; 2 3 4 import java.awt.Color; 5 import java.awt.Graphics2D; 6 import java.awt.Image; 7 import java.awt.geom.AffineTransform; 8 import java.awt.image.AffineTransformOp; 9 import java.awt.image.BufferedImage; 10 import java.io.File; 11 import java.io.IOException; 12 import java.util.Date; 13 import java.util.HashMap; 14 import java.util.Map; 15 16 import javax.imageio.ImageIO; 17 18 import com.google.zxing.BarcodeFormat; 19 import com.google.zxing.EncodeHintType; 20 import com.google.zxing.MultiFormatWriter; 21 import com.google.zxing.WriterException; 22 import com.google.zxing.common.BitMatrix; 23 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 24 25 /** 26 * 二维码生成工具类【带小图标】 27 * <br> QRCodeUtils 类的提升版本 28 * @author bxw 29 * @time 2016-07-17 22:13:45 30 * @version v1.1 31 */ 32 public class BarcodeFactory { 33 34 /** 35 * 图片格式定义 36 * @value Array 37 */ 38 private static String[] IMAGE_TYPE = {"BMP", "bmp", "jpg", "JPG", "wbmp", "jpeg", "png", "PNG", "JPEG", "WBMP", "GIF", "gif","ICON","icon"}; 39 40 /** 41 * 二维码宽度 42 */ 43 public static final int WIDTH = 260; 44 45 /** 46 * 二维码高度 47 */ 48 public static final int HEIGHT = 260; 49 50 /** 51 * 图标宽度 52 */ 53 private static final int IMAGE_WIDTH = 68; 54 /** 55 * 图标高度 56 */ 57 private static final int IMAGE_HEIGHT = 68; 58 /** 59 * 底图大小【正方形】 60 */ 61 private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2; 62 /** 63 * 底图边框 64 */ 65 private static final int FRAME_WIDTH = 5; 66 67 /** 68 * 二维码写码器 69 */ 70 private static MultiFormatWriter mutiWriter = new MultiFormatWriter(); 71 72 /** 73 * 二维码生成-方法入口 74 * @param content 内容 75 * @param width 宽度 76 * @param height 高度 77 * @param iconImagePath 图标原路径 78 * @param qrcodeImagePath 二维码存放路径 79 * @param hasFiller 80 * 比例不对时是否需要补白:true为补白; false为不补白 81 * @return 82 * 成功:返回输出图片绝对路径;失败:返回null 83 */ 84 public static String encode(String content, int width, int height, 85 String iconImagePath, String qrcodeImagePath,boolean hasFiller) { 86 try { 87 /** 88 * 图标格式校验 89 */ 90 File icon = new File(iconImagePath); 91 if(!icon.exists()){ 92 System.err.println("系统找不到图标所在文件 !"); 93 return null; 94 } 95 String iconFileName = icon.getName(); 96 // 得到上传文件的扩展名 97 String fileExtName = iconFileName.substring(iconFileName.lastIndexOf(".") + 1); 98 if(!checkIMGType(fileExtName)){ 99 System.err.println("图标格式有误 !"); 100 return null; 101 } 102 103 if(width<260||height<260){ 104 width = BarcodeFactory.WIDTH; 105 height = BarcodeFactory.HEIGHT; 106 } 107 ImageIO.write(genBarcode(content, width, height, iconImagePath,hasFiller), 108 "png", new File(qrcodeImagePath)); 109 System.err.println("二维码已生成 "+qrcodeImagePath); 110 return qrcodeImagePath; 111 } catch (IOException e) { 112 System.err.println("图片读取异常 : "+e.getMessage()); 113 } catch (WriterException e) { 114 System.err.println("图片输出异常 :"+e.getMessage()); 115 } 116 return null; 117 } 118 119 /** 120 * 图片处理方法 121 * @param content 122 * @param width 123 * @param height 124 * @param iconImagePath 125 * @param hasFiller 126 * 比例不对时是否需要补白:true为补白; false为不补白; 127 * @return 128 * @throws WriterException 129 * @throws IOException 130 */ 131 private static BufferedImage genBarcode(String content, int width, 132 int height, String iconImagePath,boolean hasFiller) throws WriterException, 133 IOException { 134 // 读取源图像 135 BufferedImage scaleImage = scale(iconImagePath, IMAGE_WIDTH, 136 IMAGE_HEIGHT, hasFiller); 137 int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT]; 138 for (int i = 0; i < scaleImage.getWidth(); i++) { 139 for (int j = 0; j < scaleImage.getHeight(); j++) { 140 srcPixels[i][j] = scaleImage.getRGB(i, j); 141 } 142 } 143 144 Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>(); 145 hint.put(EncodeHintType.CHARACTER_SET, "utf-8"); 146 hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 147 // 生成二维码 148 BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, 149 width, height, hint); 150 151 // 二维矩阵转为一维像素数组 152 int halfW = matrix.getWidth() / 2; 153 int halfH = matrix.getHeight() / 2; 154 int[] pixels = new int[width * height]; 155 156 for (int y = 0; y < matrix.getHeight(); y++) { 157 for (int x = 0; x < matrix.getWidth(); x++) { 158 // 读取图片 159 if (x > halfW - IMAGE_HALF_WIDTH 160 && x < halfW + IMAGE_HALF_WIDTH 161 && y > halfH - IMAGE_HALF_WIDTH 162 && y < halfH + IMAGE_HALF_WIDTH) { 163 pixels[y * width + x] = srcPixels[x - halfW 164 + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH]; 165 } 166 // 在图片四周形成边框 167 else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 168 && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH 169 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 170 + IMAGE_HALF_WIDTH + FRAME_WIDTH) 171 || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH 172 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 173 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 174 + IMAGE_HALF_WIDTH + FRAME_WIDTH) 175 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 176 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 177 && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 178 - IMAGE_HALF_WIDTH + FRAME_WIDTH) 179 || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH 180 && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH 181 && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH 182 + IMAGE_HALF_WIDTH + FRAME_WIDTH)) { 183 pixels[y * width + x] = 0xfffffff; 184 } else { 185 // 此处可以修改二维码的颜色,可以分别制定二维码和背景的颜色; 186 pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 187 : 0xfffffff; 188 } 189 } 190 } 191 192 BufferedImage image = new BufferedImage(width, height, 193 BufferedImage.TYPE_INT_RGB); 194 image.getRaster().setDataElements(0, 0, width, height, pixels); 195 196 return image; 197 } 198 199 /** 200 * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标 201 * 202 * @param iconImagePath 203 * 小图标源文件地址 204 * @param height 205 * 目标高度 206 * @param width 207 * 目标宽度 208 * @param hasFiller 209 * 比例不对时是否需要补白:true为补白; false为不补白; 210 * @throws IOException 211 */ 212 private static BufferedImage scale(String iconImagePath, int height, 213 int width, boolean hasFiller) throws IOException { 214 double ratio = 0.0; // 缩放比例 215 File file = new File(iconImagePath); 216 BufferedImage srcImage = ImageIO.read(file); 217 Image destImage = srcImage.getScaledInstance(width, height, 218 BufferedImage.SCALE_SMOOTH); 219 // 计算比例 220 if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { 221 if (srcImage.getHeight() > srcImage.getWidth()) { 222 ratio = (new Integer(height)).doubleValue() 223 / srcImage.getHeight(); 224 } else { 225 ratio = (new Integer(width)).doubleValue() 226 / srcImage.getWidth(); 227 } 228 AffineTransformOp op = new AffineTransformOp( 229 AffineTransform.getScaleInstance(ratio, ratio), null); 230 destImage = op.filter(srcImage, null); 231 } 232 if (hasFiller) {// 补白 233 BufferedImage image = new BufferedImage(width, height, 234 BufferedImage.TYPE_INT_RGB); 235 Graphics2D graphic = image.createGraphics(); 236 graphic.setColor(Color.white); 237 graphic.fillRect(0, 0, width, height); 238 if (width == destImage.getWidth(null)) 239 graphic.drawImage(destImage, 0, 240 (height - destImage.getHeight(null)) / 2, 241 destImage.getWidth(null), destImage.getHeight(null), 242 Color.white, null); 243 else 244 graphic.drawImage(destImage, 245 (width - destImage.getWidth(null)) / 2, 0, 246 destImage.getWidth(null), destImage.getHeight(null), 247 Color.white, null); 248 graphic.dispose(); 249 destImage = image; 250 System.err.println("INFO 图标补白已完成 "); 251 } 252 return (BufferedImage) destImage; 253 } 254 255 /** 256 * 图片格式校验 257 * @param fileExtName 258 * @return 259 */ 260 private static boolean checkIMGType(String fileExtName){ 261 boolean flag = false; 262 for (String type : IMAGE_TYPE) { 263 //-- 图片格式正确 264 if(type.toLowerCase().equals(fileExtName.toLowerCase())){ 265 flag = true; 266 break; 267 } 268 } 269 //------------图片格式校验结束 270 return flag; 271 } 272 273 /** 274 * 测试主方法入口 275 * @param args 276 */ 277 public static void main(String[] args) { 278 String codeIconPath = "C:/Users/rick/Desktop/1.jpg"; 279 String codePath = "C:/Users/rick/Desktop/"+new Date().getTime()+".png"; 280 281 /** 282 * 测试方法入口 283 */ 284 BarcodeFactory.encode("项目:晚餐定制",300, 300, codeIconPath, codePath,false); 285 } 286 }
著名: 代码只作为学习用途,谢谢 !
时间: 2024-12-25 21:23:00