/**
 * 
 */
package com.pcloud.common.utils;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.pcloud.common.constant.ImageConstant;
import com.pcloud.common.dto.BackgroudQrDto;
import com.pcloud.common.entity.UploadResultInfo;
import com.pcloud.common.enums.ImageTypeEnum;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.exceptions.FileException;
import com.pcloud.common.utils.aliyun.OssUtils;
import com.pcloud.common.utils.string.StringUtil;

/** 
 * 描述  :生成二维码
 * @author 作者: lili
 * @date 创建时间：2017年6月20日 下午6:21:34 
 * @version 1.0 
 */
public class QrcodeUtils {
	
	/**
	 * 
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(QrcodeUtils.class);
	
	private static final Integer LOGO_WIDTH = 100; // logo宽度
	private static final Integer LOGO_HEIGHT = 100; // logo高度
	private static final int IMAGE_HALF_WIDTH = LOGO_WIDTH / 2;
	private static final Integer onColor = 0xFF000000; // 前景色
	private static final Integer offColor = 0xFFFFFFFF; // 背景色
	private static final int FRAME_WIDTH = 2;
	private static MultiFormatWriter mutiWriter = new MultiFormatWriter();
	private static final Integer margin = 0; // 白边大小，取值范围0~4
	private static final ErrorCorrectionLevel level = ErrorCorrectionLevel.H; // 二维码容错率
	private static final Map<Integer, BackgroudQrDto> styleMap = new HashMap<Integer, BackgroudQrDto>();
	private static final Map<String, BackgroudQrDto> templetMap = new HashMap<String, BackgroudQrDto>();
	private static  final int color_range = 195;  
	
	static {
		styleMap.put(1, new BackgroudQrDto(130, 200, 241, 241,
				"https://oss.5rs.me/oss/uploadfe/png/c81697011c764accbb70d2fabad4de94.png",false,null,null));
		styleMap.put(2, new BackgroudQrDto(130, 200, 241, 241,
				"https://oss.5rs.me/oss/uploadfe/png/9afbac09f6a976582bcf185e2b5aa69d.png",false,null,null));
		styleMap.put(3, new BackgroudQrDto(119, 124, 249, 256,
				"https://oss.5rs.me/oss/uploadfe/png/771aa2599549d722e09252aea9be7940.png",false,null,null));
		styleMap.put(4, new BackgroudQrDto(115, 128, 243, 233,
				"https://oss.5rs.me/oss/uploadfe/png/bc6fdddbd57c2eb3f3fb74c57b94a8a4.png",false,null,null));
		styleMap.put(5, new BackgroudQrDto(185, 170, 145, 145,
				"https://oss.5rs.me/oss/uploadfe/png/608b4ff5b8dfcb005dd04c04a6ad4bc3.png",false,null,null));
		styleMap.put(6, new BackgroudQrDto(167, 231, 165, 165,
				"https://oss.5rs.me/oss/uploadfe/png/c4d7209efeb24cb4cc7b1a358522431a.png",false,null,null));
		styleMap.put(7, new BackgroudQrDto(151, 138, 264, 264,
				"https://oss.5rs.me/oss/uploadfe/png/8a16cff34c06a0181442184ab422f16f.png",false,null,null));
		styleMap.put(8, new BackgroudQrDto(98, 45, 310, 299,
				"https://oss.5rs.me/oss/uploadfe/png/2c9ceba7dee3e974257986324654cddf.png",false,null,null));
		styleMap.put(9, new BackgroudQrDto(73, 134, 252, 245,
				"https://oss.5rs.me/oss/uploadfe/png/f0e63ebb4612952b04b6027aeb6784bf.png",false,null,null));
		styleMap.put(10, new BackgroudQrDto(95, 170, 303, 281,
				"https://oss.5rs.me/oss/uploadfe/png/dc1e44f380c00a6379269f290af7a462.png",false,null,null));
		styleMap.put(11, new BackgroudQrDto(157, 285, 178, 173,
				"https://oss.5rs.me/oss/uploadfe/png/e1a0a112458035275a5addd75cad6376.png",false,null,null));
		styleMap.put(12, new BackgroudQrDto(119, 77, 263, 263,
				"https://oss.5rs.me/oss/uploadfe/png/e35ebd8922a4e44a76f234e49878eb87.png",false,null,null));
		styleMap.put(13, new BackgroudQrDto(99, 66, 303, 296,
				"https://oss.5rs.me/oss/uploadfe/png/1f34eed1dae4f7a5f75bdf141c97f78e.png",true,null,null));
		styleMap.put(14, new BackgroudQrDto(169, 219, 163, 163,
				"https://oss.5rs.me/oss/uploadfe/png/92b83fbe3e630fb14c0b21465be96594.png",false,null,null));
		styleMap.put(15, new BackgroudQrDto(120, 228, 264, 253,
				"https://oss.5rs.me/oss/uploadfe/png/5718d1b6cbdb8aa7416da85422d0586b.png",true,null,null));
		styleMap.put(16, new BackgroudQrDto(116, 126, 268, 257,
				"https://oss.5rs.me/oss/uploadfe/png/d84781cdf3b752509f29d694a1f96f62.png",false,null,null));
		styleMap.put(17, new BackgroudQrDto(115, 234, 250, 243,
				"https://oss.5rs.me/oss/uploadfe/png/a8c39088470fd144e0e254c0c77f02fe.png",false,null,null));
		styleMap.put(18, new BackgroudQrDto(181, 174, 152, 148,
				"https://oss.5rs.me/oss/uploadfe/png/be5ba8542be487853bf054d281a3e9d1.png",false,null,null));
		styleMap.put(19, new BackgroudQrDto(150, 150, 200, 200,
				"https://oss.5rs.me/oss/uploadfe/png/ad6c3ee77950c31408ab45bd04b776e4.png",false,null,null));
		styleMap.put(20, new BackgroudQrDto(238, 155, 185, 185,
				"https://oss.5rs.me/oss/uploadfe/png/4885a8ab47faaf5182c9e1ab61de7b5c.png",false,null,null));
		styleMap.put(21, new BackgroudQrDto(130, 173, 213, 213,
				"https://oss.5rs.me/oss/uploadfe/png/47c0780b7d20baf6abe1908d8bf2aa5f.png",false,null,null));
		styleMap.put(22, new BackgroudQrDto(120, 189, 259, 259,
				"https://oss.5rs.me/oss/uploadfe/png/81d0e23496f8825693103934039761d6.png",false,null,null));
		styleMap.put(23, new BackgroudQrDto(120, 189, 259, 259,
				"https://oss.5rs.me/oss/uploadfe/png/6f71c62a3552ffb596406eb34aa03ee1.png",false,null,null));
		styleMap.put(24, new BackgroudQrDto(187, 212, 134, 131,
				"https://oss.5rs.me/oss/uploadfe/jpg/92f8cf48ae80b099db6580e05d142bea.jpg",false,null,15036692)); //#e57114
		styleMap.put(25, new BackgroudQrDto(101, 95, 138, 132,
				"https://oss.5rs.me/oss/uploadfe/jpg/466b40ec470e0dc2094f5967ac7599f3.jpg",true,null,14171392));//#d83d00
		
		
		templetMap.put("K12", new BackgroudQrDto(164, 185, 296, 296,
				"https://oss.5rs.me/oss/uploadfe/jpg/f1311387f8295574ba7ec2c6a3307697.jpg",false,
				"查询每套试卷得分排名\n名师在线实时答疑\n做独家拔高题\n加入本卷备考提升圈,与数万尖子生交流学习经验",null));
		templetMap.put("PUBLIC_PROSE", new BackgroudQrDto(189, 94, 290, 290,
				"https://oss.5rs.me/oss/uploadfe/jpg/2c532e7be5250e0b69c1ecf4f9e4c80b.jpg",false,
				"看独家作者手稿\n听本书朗读音频\n读经典片段摘抄\n加入本书品读圈\n与千万书友交流阅读心得",null));
		templetMap.put("PUBLIC_NOVEL", new BackgroudQrDto(154, 119, 300, 300,
				"https://oss.5rs.me/oss/uploadfe/jpg/b984397d272d10fd4eb116ac19ee9791.jpg",false,
				"获取作者一手资讯\n看后续章节与番外剧情\n与千万书迷一起看作者在做什么",null));
		templetMap.put("SINOLOGY", new BackgroudQrDto(341, 201, 291, 291,
				"https://oss.5rs.me/oss/uploadfe/jpg/fc6fae2827e0f2100e08966ba4d3c258.jpg",false,
				"品名家独特见解\n读经典片段摘抄",null));
		templetMap.put("VACATION", new BackgroudQrDto(199, 104, 294, 280,
				"https://oss.5rs.me/oss/uploadfe/jpg/80ba7280b295da210d980001fd2f774a.jpg",false,
				"给爸爸妈妈的暑假作业\n查答案,作业查漏补缺\n难题辅导,孩子脱胎换骨",null));
		templetMap.put("IMPORTED_HIGER", new BackgroudQrDto(144, 57, 280, 277,
				"https://oss.5rs.me/oss/uploadfe/jpg/bbf300ce6746943b404249431bfb799b.jpg",false,
				"本书答案详解,看基础知识点梳理,章节重难点解析",null));
		templetMap.put("IMPORTED_SMALL", new BackgroudQrDto(139, 56, 278, 278,
				"https://oss.5rs.me/oss/uploadfe/jpg/5c35cecf18f0ccf654f08e7820f18a3a.jpg",false,
				"本书答案详解,看基础知识点梳理,章节重难点解析",null));
		templetMap.put("MILITARY", new BackgroudQrDto(152, 126, 266, 247,
				"https://oss.5rs.me/oss/uploadfe/jpg/b94f22852977316abf4212563017e313.jpg",false,
				"看关键事件解密\n挖掘战役背后真相\n交流当今军事事件",null));
		templetMap.put("EXTRACURRICULAR", new BackgroudQrDto(168, 138, 267, 267,
				"https://oss.5rs.me/oss/uploadfe/jpg/f0cc9be959965c5a5707b1cea0ec67a5.jpg",false,
				"看书中隐秘小剧情\n亲子互动小游戏,\n拉进家长与孩子的距离",null));
		templetMap.put("GERIATRIC", new BackgroudQrDto(123, 131, 328, 328,
				"https://oss.5rs.me/oss/uploadfe/jpg/e3921c2f36554dbf09e14b7bccde647e.jpg",false,
				"听本书配套音频\n看名师示范视频",null));
		templetMap.put("CELEBRITY", new BackgroudQrDto(163, 79, 287, 287,
				"https://oss.5rs.me/oss/uploadfe/jpg/df425751842343949509e3b524d1412c.jpg",false,
				"品读名人经典语录\n收藏名人成长相册\n一张图厘清他的人际关系\n探寻名人成功背后的故事",null));
		templetMap.put("CHILD_PUFFIN", new BackgroudQrDto(153, 101, 280, 268,
				"https://oss.5rs.me/oss/uploadfe/jpg/ebc166782f031be6f9f262b4a9fb7a1d.jpg",false,
				"听本书配套故事音频\n品鉴书中经典段落摘抄\n解密本书10大隐藏剧情\n加入读者圈与千万读者交流互动",null));
		templetMap.put("CHILD_SINOLOGY", new BackgroudQrDto(146, 100, 260, 260,
				"https://oss.5rs.me/oss/uploadfe/jpg/393744c6199e92d2311ebc844b3048d3.jpg",false,
				"本书伴读指南\n读章节最美译文\n看名家偏爱的经典桥段",null));
		templetMap.put("CHILD_INTEREST", new BackgroudQrDto(162, 86, 295, 295,
				"https://oss.5rs.me/oss/uploadfe/jpg/9b4bbc9f8a2db5d365a616f13a6a141a.jpg",false,
				"听故事,帮孩子练就纯正发音\n亲子互动活动,让孩子在游戏中成长\n看单词记忆卡片,对孩子开展启蒙教育",null));
		templetMap.put("SCIENCE", new BackgroudQrDto(116, 96, 326, 327,
				"https://oss.5rs.me/oss/uploadfe/jpg/cb74a6ab3290855f49d2f764d42a364d.jpg",false,
				"看本书生活实用小窍门",null));
		templetMap.put("PROMOTE", new BackgroudQrDto(92, 38, 285, 285,
				"https://oss.5rs.me/oss/uploadfe/jpg/bc1d1b1c8f7c8432ad08fb4fe7dec3da.jpg",false,
				"共享本书经典详解案例\n专业工具包助你商业实战",null));
		templetMap.put("PROFESSIONAL", new BackgroudQrDto(140, 136, 408, 408,
				"https://oss.5rs.me/oss/uploadfe/jpg/1c08a0787ee7571b24492a74552030d1.jpg",false,
				"查看往届真题,把握命题方向\n浏览本书大纲,提炼学期重点\n掌握10大典型例题,轻松通过考试\n扫码关注,加入读者交流圈,\n获取本书以上配套资源",null));
		templetMap.put("SPECIAL_HIGER", new BackgroudQrDto(122, 69, 288, 288,
				"https://oss.5rs.me/oss/uploadfe/jpg/92a93f11b7512177bf18d9d2b115a01f.jpg",false,
				"一线名师在线答疑\n查看本书10大易错知识点\n获取典型例题解答技巧\n揭秘高考状元高分秘笈",null));
		templetMap.put("SPECIAL_SMALL", new BackgroudQrDto(123, 70, 288, 288,
				"https://oss.5rs.me/oss/uploadfe/jpg/1c9cf68359f7477559fcafbab6fa9390.jpg",false,
				"名师助阵,在线答疑\n查看典型例题解析,斩获高分秘诀\n提炼10大易错知识点,横扫知识盲区",null));
		templetMap.put("PUBLIC_JOURNAL", new BackgroudQrDto(147, 176, 248, 248,
				"https://oss.5rs.me/oss/uploadfe/jpg/bf9e0f8e1d6f6f636184602aed3c2d19.jpg",false,
				"线上增刊品牌名+独家呈现",null));
		templetMap.put("other", new BackgroudQrDto(626, 452, 385, 385,
				"https://oss.5rs.me/oss/uploadfe/png/1070da3aa27a8334dcd898187e85dcac.png",false,
				null,null));
//		templetMap.put("", new BackgroudQrDto(189, 94, 290, 290,
//				"https://oss.5rs.me/oss/uploadfe/jpg/87d3f8ca06685c50ff6a39eb1efe2f2d.jpg",false));
//		templetMap.put("", new BackgroudQrDto(189, 94, 290, 290,
//				"https://oss.5rs.me/oss/uploadfe/jpg/87d3f8ca06685c50ff6a39eb1efe2f2d.jpg",false));
	}
	
	/**
	 * 创建二维码
	 * 
	 * @param content
	 *            二维码响应地址
	 * @return
	 * @throws Exception
	 */
	public static String create(String url) throws BizException {
		LOGGER.info("【二维码】创建二维码,<START>.[url]=" + url);
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, level);
		hints.put(EncodeHintType.MARGIN, margin); // 设置白边
		try {
			// 生成矩阵
			BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH,
					ImageConstant.QRCODE_HEIGHT, hints);
			BufferedImage bufferedImage = toBufferedImage(bitMatrix, onColor);
			bufferedImage.flush();
			return uploadImage(bufferedImage);
		} catch (Exception e) {
			LOGGER.error("【二维码】创建二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建二维码失败");
		}
	}

	/**
	 * 创建带颜色的二维码
	 * @param url
	 * @param onColor
	 * @return
	 * @throws BizException
	 */
	public static String create(String url, Integer onColor, Integer marginNum) throws BizException {
		LOGGER.info("【二维码】创建带颜色的二维码,<START>.[url]=" + url+"[onClor]="+onColor);
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
		hints.put(EncodeHintType.MARGIN, marginNum); // 设置白边
		try {
			// 生成矩阵
			BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH,
					ImageConstant.QRCODE_HEIGHT, hints);
			BufferedImage bufferedImage = toBufferedImage(bitMatrix, onColor);
			bufferedImage.flush();
			return uploadImage(bufferedImage);
		} catch (Exception e) {
			LOGGER.error("【二维码】创建二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建二维码失败");
		}
	}

	
	/**
	 * 创建带颜色的二维码
	 * @param url
	 * @param onColor
	 * @return
	 * @throws BizException
	 */
	public static String create(String url, Integer onColor) throws BizException {
		LOGGER.info("【二维码】创建带颜色的二维码,<START>.[url]=" + url+"[onClor]="+onColor);
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, level);
		hints.put(EncodeHintType.MARGIN, margin); // 设置白边
		try {
			// 生成矩阵
			BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH,
					ImageConstant.QRCODE_HEIGHT, hints);
			BufferedImage bufferedImage = toBufferedImage(bitMatrix, onColor);
			bufferedImage.flush();
			return uploadImage(bufferedImage);
		} catch (Exception e) {
			LOGGER.error("【二维码】创建二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建二维码失败");
		}
	}

	
	/**
	 * 创建渐变色二维码
	 * 
	 * @param content
	 *            二维码响应地址
	 * @return
	 * @throws Exception
	 */
	public static String createGradientColorQr(String url, Color newColor, Color oldColor) throws BizException {
		LOGGER.info("【二维码】创建渐变色二维码,<START>.[url]=" + url+"newColor="+newColor+"oldColor="+oldColor);
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, level);
		hints.put(EncodeHintType.MARGIN, margin); // 设置白边
		try {
			// 生成矩阵
			BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH,
					ImageConstant.QRCODE_HEIGHT, hints);
			BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
			bufferedImage.flush();
			// 设置二维码颜色
			int[] pixels = new int[ImageConstant.QRCODE_WITH * ImageConstant.QRCODE_HEIGHT];
			for (int y = 0; y < bitMatrix.getHeight(); y++) {
				for (int x = 0; x < bitMatrix.getWidth(); x++) {
					// 二维码颜色
					int num1 = (int) (oldColor.getRed()
							- (oldColor.getRed() - newColor.getRed()) * 1.0 / bitMatrix.getHeight() * (y + 1));
					int num2 = (int) (oldColor.getGreen()
							- (oldColor.getGreen() - newColor.getGreen()) * 1.0 / bitMatrix.getHeight() * (y + 1));
					int num3 = (int) (oldColor.getBlue()
							- (oldColor.getBlue() - newColor.getBlue()) * 1.0 / bitMatrix.getHeight() * (y + 1));
					Color color = new Color(num1, num2, num3);
					int colorInt = color.getRGB();
					// 此处可以修改二维码的颜色，可以分别制定二维码和背景的颜色；
					pixels[y * ImageConstant.QRCODE_WITH + x] = bitMatrix.get(x, y) ? colorInt : 16777215;
				}
			}
			BufferedImage image = new BufferedImage(ImageConstant.QRCODE_WITH, ImageConstant.QRCODE_HEIGHT,
					BufferedImage.TYPE_INT_RGB);
			image.getRaster().setDataElements(0, 0, ImageConstant.QRCODE_WITH, ImageConstant.QRCODE_HEIGHT, pixels);
			return uploadImage(image);
		} catch (Exception e) {
			LOGGER.error("【二维码】创建渐变色二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建渐变色二维码失败");
		}
	}

	/**
	 * 创建带logo二维码
	 * 
	 * @param content
	 *            二维码响应地址
	 * @return
	 * @throws Exception
	 */
	public static String createLogoQr(String url, String logoPath, Integer onColor) throws BizException {
		LOGGER.info("【二维码】创建带logo二维码,<START>.[url]=" + url+",logoPath="+logoPath+",onColor="+onColor);
		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
		hints.put(EncodeHintType.ERROR_CORRECTION, level);
		hints.put(EncodeHintType.MARGIN, margin); // 设置白边
		try {
			// 生成矩阵
			BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH,
					ImageConstant.QRCODE_HEIGHT, hints);
			BufferedImage image = toBufferedImage(bitMatrix, onColor);
			Graphics2D gs = image.createGraphics();
			// 载入logo
 			byte[] file = FileUtils.downloadByteFromUrl(logoPath);
			ByteArrayInputStream in = new ByteArrayInputStream(file);
			BufferedImage srcImage = ImageIO.read(in);
			Image img = srcImage.getScaledInstance(LOGO_WIDTH, LOGO_HEIGHT, BufferedImage.SCALE_SMOOTH);
			int x = (image.getWidth() - LOGO_WIDTH) / 2;
			int y = (image.getHeight() - LOGO_HEIGHT) / 2;
			gs.drawImage(img, x, y, LOGO_WIDTH, LOGO_HEIGHT, null);
			BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
			gs.setStroke(stroke);// 设置笔画对象
			// 指定弧度的圆角矩形
			RoundRectangle2D.Float round = new RoundRectangle2D.Float(x, y, LOGO_WIDTH, LOGO_HEIGHT, 20, 20);
			gs.setColor(Color.WHITE);
			gs.draw(round);// 绘制圆弧矩形
			gs.dispose();
			img.flush();
			return uploadImage(image);
		} catch (Exception e) {
			LOGGER.error("【二维码】创建带logo二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建带logo二维码失败");
		}
	}
	 
	/**
	 * 图片上传文件服务器返回url
	 * 
	 * @param image
	 * @return
	 * @throws BizException
	 */
	public static String uploadImage(BufferedImage image) throws BizException {
		UploadResultInfo uploadResultInfo = null;
		try {
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			ImageIO.write(image, ImageTypeEnum.PNG.value, os);
			uploadResultInfo = OssUtils.uploadFileByte(os.toByteArray(), UUIDUitl.taskName(), ImageTypeEnum.PNG.value);
			os.close();
			return uploadResultInfo == null ? null : uploadResultInfo.getUrl();
		} catch (Exception e) {
			LOGGER.error("【二维码】上传二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "上传二维码失败");
		}
	}

	/**
	 * 创建渐变色带logo的二维码
	 * @param content
	 * @param srcImagePath
	 * @return
	 */
	public static String createGradientColorLogoQr(String content, String srcImagePath,Color newColor,Color oldColor) {
		LOGGER.info("【二维码】 创建渐变色带logo的二维码,<START>.[content]=" + content+",srcImagePath="+srcImagePath+",newColor="+newColor+"oldColor="+oldColor);
		try {
			BufferedImage scaleImage = scale(srcImagePath, LOGO_WIDTH, LOGO_HEIGHT, true);
			int[][] srcPixels = new int[LOGO_WIDTH][LOGO_HEIGHT];
			for (int i = 0; i < scaleImage.getWidth(); i++) {
				for (int j = 0; j < scaleImage.getHeight(); j++) {
					srcPixels[i][j] = scaleImage.getRGB(i, j);
				}
			}
			Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>();
			hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
			hint.put(EncodeHintType.ERROR_CORRECTION, level);
			hint.put(EncodeHintType.MARGIN, margin);  //设置白边
			// 生成二维码
			BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, ImageConstant.QRCODE_WITH, ImageConstant.QRCODE_HEIGHT, hint);
			deleteWhite(matrix);
			// 二维矩阵转为一维像素数组
			int halfW = matrix.getWidth() / 2;
			int halfH = matrix.getHeight() / 2;
			int[] pixels = new int[ImageConstant.QRCODE_WITH * ImageConstant.QRCODE_HEIGHT];
			for (int y = 0; y < matrix.getHeight(); y++) {
				for (int x = 0; x < matrix.getWidth(); x++) {
					// 左上角颜色,根据自己需要调整颜色范围和颜色
					if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH
							&& y < halfH + IMAGE_HALF_WIDTH) {
						pixels[y * ImageConstant.QRCODE_WITH + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];
					} else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH
							&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)
							|| (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
									&& y > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
									&& y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)
							|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
									&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH
									&& y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH)
							|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
									&& y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH
									&& y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) {
						pixels[y * ImageConstant.QRCODE_WITH + x] = 0xfffffff;
						// 在图片四周形成边框
					} else {
						// 二维码颜色  13 72 107   50 165 162
						int num1 = (int) (oldColor.getRed() - (oldColor.getRed() - newColor.getRed())*1.0 / matrix.getHeight() * (y + 1));
						int num2 = (int) (oldColor.getGreen() - (oldColor.getGreen() - newColor.getGreen())*1.0 / matrix.getHeight() * (y + 1));
						int num3 = (int) (oldColor.getBlue() - (oldColor.getBlue() - newColor.getBlue()) *1.0/ matrix.getHeight() * (y + 1));
						Color color = new Color(num1, num2, num3);
						int colorInt = color.getRGB();
						// 此处可以修改二维码的颜色，可以分别制定二维码和背景的颜色；
						pixels[y * ImageConstant.QRCODE_WITH + x] = matrix.get(x, y) ? colorInt : 16777215;
						// 0x000000:0xffffff
					}
				}
			}
			BufferedImage image = new BufferedImage(ImageConstant.QRCODE_WITH, ImageConstant.QRCODE_HEIGHT, BufferedImage.TYPE_INT_RGB);
			image.getRaster().setDataElements(0, 0, ImageConstant.QRCODE_WITH, ImageConstant.QRCODE_HEIGHT, pixels);
			return uploadImage(image);
		} catch (BizException e) {
			throw new BizException(e.getCode(), e.getMessage());
		}catch (Exception e) {
			LOGGER.error("【二维码】创建渐变色带logo的二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建渐变色带logo的二维码失败");
		}

	}
	
	  
	  private static BufferedImage scale(String srcImageFile, int height,
		      int width, boolean hasFiller) throws IOException,BizException {
		    double ratio = 1.0; // 缩放比例
		    byte[] file = FileUtils.downloadByteFromUrl(srcImageFile);
		    ByteArrayInputStream in = new ByteArrayInputStream(file);
		    BufferedImage srcImage = null;
		    try{
		    	  srcImage = ImageIO.read(in); 
		    }catch(Exception e){
		    	LOGGER.warn("不支持的文件格式srcImageFile="+srcImageFile,e);
		    	throw new FileException(FileException.FILE_READ_FAILURE,"不支持的文件格式");
		    }
		  
		    Image destImage = srcImage.getScaledInstance(width, height,
		        BufferedImage.SCALE_SMOOTH);
		    // 计算比例  
		    if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {
		      if (srcImage.getHeight() > srcImage.getWidth()) {
		        ratio = (new Integer(height)).doubleValue()
		            / srcImage.getHeight();
		      } else {
		        ratio = (new Integer(width)).doubleValue()
		            / srcImage.getWidth();
		      }
		      AffineTransformOp op = new AffineTransformOp(
		          AffineTransform.getScaleInstance(ratio, ratio), null);
		      destImage = op.filter(srcImage, null);
		    }
		    if (hasFiller) {
		      // 补白
		      BufferedImage image = new BufferedImage(width, height,
		          BufferedImage.TYPE_INT_RGB);
		      Graphics2D graphic = image.createGraphics();
		      graphic.setColor(Color.white);
		      graphic.fillRect(0, 0, width, height);
		      if (width == destImage.getWidth(null))
		        graphic.drawImage(destImage, 0,
		            (height - destImage.getHeight(null)) / 2,
		            destImage.getWidth(null), destImage.getHeight(null),
		            Color.white, null);
		      else
		        graphic.drawImage(destImage,
		            (width - destImage.getWidth(null)) / 2, 0,
		            destImage.getWidth(null), destImage.getHeight(null),
		            Color.white, null);
		      graphic.dispose();
		      destImage = image;
		    }
		    return (BufferedImage) destImage;
		  }
	
   
   /**
    * matrix转BufferedImage
    * @param matrix
    * @param offColor 前景色
    * @param onColor 背景色
    * @return
    */
   public static BufferedImage toBufferedImage(BitMatrix matrix,Integer onColor){  
       int width = matrix.getWidth();  
       int height = matrix.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, matrix.get(x, y) ? onColor : offColor);  
           }  
       }  
       return image;     
   } 
   
   
   public static BitMatrix deleteWhite(BitMatrix matrix){  
       int[] rec = matrix.getEnclosingRectangle();  
       int resWidth = rec[2] + 1;  
       int resHeight = rec[3] + 1;  
     
       BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);  
       resMatrix.clear();  
       for (int i = 0; i < resWidth; i++) {  
           for (int j = 0; j < resHeight; j++) {  
               if (matrix.get(i + rec[0], j + rec[1]))  
                   resMatrix.set(i, j);  
           }  
       }  
       return resMatrix;  
   } 

   
   /**
    * 合成二维码
    * @param qrcodeUrl
    * @return
    * @throws IOException 
    */
	public static String getStyleQr(String qrcodeUrl, Integer backgroundType, String url) throws BizException {
		LOGGER.info("合成二维码qrcodeUrl="+qrcodeUrl+"backgroundType="+backgroundType+"url="+url);
		try {
			BackgroudQrDto backgroudQrDto = styleMap.get(backgroundType);
			String backgroundUrl = "";
			if (backgroudQrDto != null) {
				//获取背景图片
				byte[] backGroundFirstUrl = FileUtils.downloadByteFromUrl(backgroudQrDto.getBackgroundUrl());
				ByteArrayInputStream backGround = new ByteArrayInputStream(backGroundFirstUrl);
				BufferedImage bg = ImageIO.read(backGround);
				Graphics2D g = bg.createGraphics();
				
				if(backgroudQrDto.getQrcodeColor() != null){
					qrcodeUrl = create(url, backgroudQrDto.getQrcodeColor(),0);
				}
				if(backgroudQrDto.getIsTransparent()){
					qrcodeUrl = convert(qrcodeUrl);
				}
				//下载二维码图片
				byte[] qrcode = FileUtils.downloadByteFromUrl(qrcodeUrl);
				ByteArrayInputStream in = new ByteArrayInputStream(qrcode);
				BufferedImage qrcodeImage = ImageIO.read(in);
				//合成两张图片
				g.drawImage(qrcodeImage, backgroudQrDto.getX(), backgroudQrDto.getY(), backgroudQrDto.getWidth(),
						backgroudQrDto.getHeight(), null);
				g.dispose();
				backgroundUrl = uploadImage(bg);
				qrcodeImage.flush();
				bg.flush();
			}
			if (StringUtil.isEmpty(backgroundUrl)) {
				backgroundUrl = qrcodeUrl;
			}
			return backgroundUrl;
		} catch (Exception e) {
			LOGGER.error("【二维码】合成二维码失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建二维码失败");
		}
	}
	public static void main(String[] args) {
//		System.out.println(OssUtils.urlAddKeyLong(setFont2Qr("https://oss.5rs.me/oss/upload/image/png/40925b85d39c4b619ab7fdf676455cbb.png","CELEBRITY",	
//				"品读名人经典语录\n收藏名人成长相册\n一张图厘清他的人际关系\n探寻名人成功背后的故事")));
//		System.out.println(OssUtils.urlAddKeyLong(getStyleQr("",26,"http://weixin.qq.com/q/SUSF-s-mKJ1RIzuaqmib")));
//		String color = "#d83d00";
//		System.out.println(Integer.parseInt(color.replaceAll("#", ""), 16));
	}
	  /**
	    * 合成二维码并贴字
	    * @param qrcodeUrl
	    * @return
	    * @throws IOException 
	    */
		public static String setFont2Qr(String qrcodeUrl, String typeCode,String font) throws BizException {
			LOGGER.info(" 合成二维码并贴字,参数qrcodeUrl="+qrcodeUrl+",typeCode="+typeCode+",font="+font);
			try {
				BackgroudQrDto backgroudQrDto = templetMap.get(typeCode);
				String backgroundUrl = "";
				String remark = backgroudQrDto.getRemark();
				if (backgroudQrDto != null) {
					//文字不为空且不相等时，修改文字内容
					if(!(StringUtil.isEmpty(font)|| remark.equals(font))){
						backgroudQrDto = templetMap.get("other");
					}
					//获取背景图片
					byte[] backGroundFirstUrl = FileUtils.downloadByteFromUrl(backgroudQrDto.getBackgroundUrl());
					ByteArrayInputStream backGround = new ByteArrayInputStream(backGroundFirstUrl);
					BufferedImage bg = ImageIO.read(backGround);
					Graphics2D g = bg.createGraphics();
					
					//下载二维码图片
					byte[] qrcode = FileUtils.downloadByteFromUrl(qrcodeUrl);
					ByteArrayInputStream in = new ByteArrayInputStream(qrcode);
					BufferedImage qrcodeImage = ImageIO.read(in);
					//合成两张图片
					g.drawImage(qrcodeImage, backgroudQrDto.getX(), backgroudQrDto.getY(), backgroudQrDto.getWidth(),
							backgroudQrDto.getHeight(), null);
					if(!(StringUtil.isEmpty(font)|| remark.equals(font))){
						g.setColor(Color.BLACK); // 设置画笔颜色
						// 设置字体
						int x = 149;
						int y = 390;
						int total =10;
						g.setFont(new Font("宋体", Font.LAYOUT_NO_LIMIT_CONTEXT, 25));
						String[] fonts = font.split("/n");
						for(int i = 0 ; i < (fonts.length > 10 ? 10:fonts.length) ; i++){
							for(int j = 0; j <=fonts[i].length()/14; j++){
								if(j == fonts[i].length()/14){
									g.drawString(fonts[i].substring(j*14,fonts[i].length()), x, y);
								}else {
									g.drawString(fonts[i].substring(j*14,(j+1)*14), x, y);
								}
								total--;
								y+=50;
								if(total < 0){
									break;
								}
							}
						}
					}
				
					g.dispose();
					backgroundUrl = uploadImage(bg);
					qrcodeImage.flush();
					bg.flush();
				}
				if (StringUtil.isEmpty(backgroundUrl)) {
					backgroundUrl = qrcodeUrl;
				}
				LOGGER.info(" 合成二维码并贴字【END】backgroundUrl="+backgroundUrl);
				return backgroundUrl;
			} catch (Exception e) {
				LOGGER.error("【二维码】创建二维码失败,<ERROR>:" + e.getMessage(), e);
				throw new FileException(FileException.FILE_UPLOAD_FAILURE, "创建二维码失败");
			}
		}
	
	
	public static String convert(String qrcodeUrl){
		LOGGER.info("二维码设置背景透明qrcodeUrl:"+qrcodeUrl);

		//下载二维码图片
		try {
		byte[] qrcode = FileUtils.downloadByteFromUrl(qrcodeUrl);

		ByteArrayInputStream in = new ByteArrayInputStream(qrcode);

		BufferedImage qrcodeImage = ImageIO.read(in);

		ImageIcon imageIcon = new ImageIcon(qrcodeImage);  

        BufferedImage newBufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(),BufferedImage.TYPE_4BYTE_ABGR_PRE);  

        Graphics2D g2D = (Graphics2D) newBufferedImage.getGraphics();  

        g2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());  

        int alpha = 255;  

        for (int j1 = newBufferedImage.getMinY(); j1 < newBufferedImage.getHeight(); j1++) {  

        	for (int j2 = newBufferedImage.getMinX(); j2 < newBufferedImage.getWidth(); j2++) {  

        		int rgb = newBufferedImage.getRGB(j2, j1);  

                if (colorInRange(rgb))  

                	alpha = 0;  

                else  

                    alpha = 255;  

                rgb = (alpha << 24) | (rgb & 0x00ffffff);  

                newBufferedImage.setRGB(j2, j1, rgb);  

        	}  

        }  

        g2D.drawImage(newBufferedImage, 0, 0, imageIcon.getImageObserver());  

        newBufferedImage.flush();

		return uploadImage(newBufferedImage);
		} catch (Exception e) {
			LOGGER.error("【二维码】二维码设置背景透明失败,<ERROR>:" + e.getMessage(), e);
			throw new FileException(FileException.FILE_UPLOAD_FAILURE, "二维码设置背景透明失败");
		}
	}

	 public static boolean colorInRange(int color) {  

	        int red = (color & 0xff0000) >> 16;  

	        int green = (color & 0x00ff00) >> 8;  

	        int blue = (color & 0x0000ff);

	        if (red >= color_range && green >= color_range && blue >= color_range)  

	            return true;  

	        return false;  

	    } 


}
