diff --git a/mallinkPosApi/pom.xml b/mallinkPosApi/pom.xml index 79eda0078..c41f807bc 100644 --- a/mallinkPosApi/pom.xml +++ b/mallinkPosApi/pom.xml @@ -22,6 +22,11 @@ spring-boot-starter-test test + + com.google.zxing + core + 3.3.0 + diff --git a/mallinkPosApi/src/main/java/com/iformall/PosApplication.java b/mallinkPosApi/src/main/java/com/iformall/PosApplication.java index e97ef4230..c89c4bc2e 100644 --- a/mallinkPosApi/src/main/java/com/iformall/PosApplication.java +++ b/mallinkPosApi/src/main/java/com/iformall/PosApplication.java @@ -9,8 +9,8 @@ import org.springframework.context.annotation.Bean; import tk.mybatis.spring.annotation.MapperScan; /** - * @author chenkx - * @date 2017-12-26 + * @author Stormeye + * @date 2019-08-08 */ @SpringBootApplication @MapperScan(basePackages = {"com.iformall.mapper"}) @@ -27,6 +27,9 @@ public class PosApplication { @Value("${fm.open}") private boolean fmOpen; + @Value("${fm.upload_dir}") + private String uploadDir; + @Bean public boolean isFmException() { return fmException; @@ -42,6 +45,11 @@ public class PosApplication { return fmOpen; } + @Bean + public String fmUploadDir() { + return uploadDir; + } + public static void main(String[] args) { SpringApplication.run(PosApplication.class, args); diff --git a/mallinkPosApi/src/main/java/com/iformall/service/PosService.java b/mallinkPosApi/src/main/java/com/iformall/service/PosService.java index 1165f19c2..38fe39cd6 100644 --- a/mallinkPosApi/src/main/java/com/iformall/service/PosService.java +++ b/mallinkPosApi/src/main/java/com/iformall/service/PosService.java @@ -1,7 +1,5 @@ package com.iformall.service; -import com.iformall.domain.po.WxCoupon; -import com.iformall.domain.vo.WxCouponOrderCVo; import com.iformall.enums.EnumVerifyActionType; import com.iformall.exception.MallinkException; import org.springframework.web.bind.annotation.RequestBody; diff --git a/mallinkPosApi/src/main/java/com/iformall/utils/BufferedImageLuminanceSource.java b/mallinkPosApi/src/main/java/com/iformall/utils/BufferedImageLuminanceSource.java new file mode 100644 index 000000000..8d6d627ff --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/utils/BufferedImageLuminanceSource.java @@ -0,0 +1,94 @@ +package com.iformall.utils; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import com.google.zxing.LuminanceSource; + +/** + * @author Stormeye + */ +public class BufferedImageLuminanceSource extends LuminanceSource { + private final BufferedImage image; + private final int left; + private final int top; + + BufferedImageLuminanceSource(BufferedImage image) { + this(image, 0, 0, image.getWidth(), image.getHeight()); + } + + BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) { + super(width, height); + + int sourceWidth = image.getWidth(); + int sourceHeight = image.getHeight(); + if (left + width > sourceWidth || top + height > sourceHeight) { + throw new IllegalArgumentException("Crop rectangle does not fit within image data."); + } + + for (int y = top; y < top + height; y++) { + for (int x = left; x < left + width; x++) { + if ((image.getRGB(x, y) & 0xFF000000) == 0) { + // = white + image.setRGB(x, y, 0xFFFFFFFF); + } + } + } + + this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY); + this.image.getGraphics().drawImage(image, 0, 0, null); + this.left = left; + this.top = top; + } + + @Override + public byte[] getRow(int y, byte[] row) { + if (y < 0 || y >= getHeight()) { + throw new IllegalArgumentException("Requested row is outside the image: " + y); + } + int width = getWidth(); + if (row == null || row.length < width) { + row = new byte[width]; + } + image.getRaster().getDataElements(left, top + y, width, 1, row); + return row; + } + + @Override + public byte[] getMatrix() { + int width = getWidth(); + int height = getHeight(); + int area = width * height; + byte[] matrix = new byte[area]; + image.getRaster().getDataElements(left, top, width, height, matrix); + return matrix; + } + + @Override + public boolean isCropSupported() { + return true; + } + + @Override + public LuminanceSource crop(int left, int top, int width, int height) { + return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height); + } + + @Override + public boolean isRotateSupported() { + return true; + } + + @Override + public LuminanceSource rotateCounterClockwise() { + int sourceWidth = image.getWidth(); + int sourceHeight = image.getHeight(); + AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth); + BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY); + Graphics2D g = rotatedImage.createGraphics(); + g.drawImage(image, transform, null); + g.dispose(); + int width = getWidth(); + return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width); + } +} diff --git a/mallinkPosApi/src/main/java/com/iformall/utils/QRCodeUtil.java b/mallinkPosApi/src/main/java/com/iformall/utils/QRCodeUtil.java new file mode 100644 index 000000000..b531319bf --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/utils/QRCodeUtil.java @@ -0,0 +1,164 @@ +package com.iformall.utils; + +import java.awt.BasicStroke; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Shape; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.OutputStream; +import java.util.Hashtable; +import javax.imageio.ImageIO; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.Result; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +public class QRCodeUtil { + private static final String CHARSET = "utf-8"; + private static final String FORMAT_NAME = "JPG"; + /** + * 二维码尺寸 + */ + private static final int QRCODE_SIZE = 300; + /** + * LOGO宽度 + */ + private static final int WIDTH = 60; + /** + * LOGO高度 + */ + private static final int HEIGHT = 60; + + private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception { + Hashtable hints = new Hashtable(); + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + hints.put(EncodeHintType.CHARACTER_SET, CHARSET); + hints.put(EncodeHintType.MARGIN, 1); + BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, + hints); + int width = bitMatrix.getWidth(); + int height = bitMatrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); + } + } + if (imgPath == null || "".equals(imgPath)) { + return image; + } + // 插入图片 + QRCodeUtil.insertImage(image, imgPath, needCompress); + return image; + } + + private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception { + File file = new File(imgPath); + if (!file.exists()) { + System.err.println("" + imgPath + " 该文件不存在!"); + return; + } + Image src = ImageIO.read(new File(imgPath)); + int width = src.getWidth(null); + int height = src.getHeight(null); + // 压缩LOGO + if (needCompress) { + if (width > WIDTH) { + width = WIDTH; + } + if (height > HEIGHT) { + height = HEIGHT; + } + Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH); + BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics g = tag.getGraphics(); + // 绘制缩小后的图 + g.drawImage(image, 0, 0, null); + g.dispose(); + src = image; + } + // 插入LOGO + Graphics2D graph = source.createGraphics(); + int x = (QRCODE_SIZE - width) / 2; + int y = (QRCODE_SIZE - height) / 2; + graph.drawImage(src, x, y, width, height, null); + Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6); + graph.setStroke(new BasicStroke(3f)); + graph.draw(shape); + graph.dispose(); + } + + public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception { + BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); + mkdirs(destPath); + // String file = new Random().nextInt(99999999)+".jpg"; + // ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file)); + ImageIO.write(image, FORMAT_NAME, new File(destPath)); + } + + public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception { + BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); + return image; + } + + public static void mkdirs(String destPath) { + File file = new File(destPath); + // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常) + if (!file.exists() && !file.isDirectory()) { + file.mkdirs(); + } + } + + public static void encode(String content, String imgPath, String destPath) throws Exception { + QRCodeUtil.encode(content, imgPath, destPath, false); + } + // 被注释的方法 + /* + * public static void encode(String content, String destPath, boolean + * needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath, + * needCompress); } + */ + + public static void encode(String content, String destPath) throws Exception { + QRCodeUtil.encode(content, null, destPath, false); + } + + public static void encode(String content, String imgPath, OutputStream output, boolean needCompress) + throws Exception { + BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); + ImageIO.write(image, FORMAT_NAME, output); + } + + public static void encode(String content, OutputStream output) throws Exception { + QRCodeUtil.encode(content, null, output, false); + } + + public static String decode(File file) throws Exception { + BufferedImage image; + image = ImageIO.read(file); + if (image == null) { + return null; + } + BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); + BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); + Result result; + Hashtable hints = new Hashtable(); + hints.put(DecodeHintType.CHARACTER_SET, CHARSET); + result = new MultiFormatReader().decode(bitmap, hints); + String resultStr = result.getText(); + return resultStr; + } + + public static String decode(String path) throws Exception { + return QRCodeUtil.decode(new File(path)); + } +} diff --git a/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java b/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java index 4b2ffeb21..db4e04ab2 100644 --- a/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java +++ b/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.iformall.PosApplication; import com.iformall.pay.WxPayConstant; import com.iformall.pay.WxPayment; +import com.iformall.utils.QRCodeUtil; import org.junit.Assert; import org.junit.FixMethodOrder; import org.junit.Test; @@ -100,6 +101,33 @@ public class PosAppTest { Assert.assertEquals(resSigned, true); } + @Test + public void pQrCodeTest() { + // 存放在二维码中的内容 + String text = "https://ctest.malls.iformall.com/order/1"; + // 嵌入二维码的图片路径 + String imgPath = ""; + // 生成的二维码的路径及名称 + String destPath = "/Users/stormeye/Downloads/MyWork/bk/qr.jpg"; + try { + //生成二维码 + QRCodeUtil.encode(text, imgPath, destPath, true); + } catch (Exception e) { + System.out.println("生成二维码异常"); + e.printStackTrace(); + } + // 解析二维码,这里只是将上面的text解析出来了,所以扫描结果就是一串字符串 + String str = null; + try { + str = QRCodeUtil.decode(destPath); + } catch (Exception e) { + System.out.println("解析二维码异常"); + e.printStackTrace(); + } + // 打印出解析出的内容 + System.out.println(str); + } + @Test public void getMemTest() throws Exception { Map reqObj = new HashMap<>();