java 實(shí)現(xiàn)圖片合成,并添加文字
最近公司一個(gè)需要,需要把商品的優(yōu)惠卷分享鏈接,生成一個(gè)二維碼然后和商品主圖合成一張,并且在新合成的主圖增加商品信息的描述,好了直接看合成后圖片的樣式
下面我就直接貼代碼,首先是Contorller層
/** * 淘寶二維碼,商品主圖,合成一張圖 * * @param pictUrl * @param request * @param response * @throws IOException */ @RequestMapping("/getTaoBaoqQRCode") public void getTaoBaoqQRCode(TaoBaoQRCode taoBaoQRCode, HttpServletRequest request, HttpServletResponse response) throws IOException { ServletOutputStream os = null; InputStream buffin = null; try { // 二維碼 String couponUlr = "https:" + taoBaoQRCode.getCouponShareUrl();// 高額卷分享鏈接 byte[] imgByte = QrCodeUtil.createQrCode2Bytes(250, 250, couponUlr); buffin = new ByteArrayInputStream(imgByte); BufferedImage couponImage = ImageIO.read(buffin); // 商品主圖 String imageUrl = "https:" + taoBaoQRCode.getPictUrl(); URL url = new URL(imageUrl); BufferedImage picImage = ImageIO.read(url); BufferedImage modifyImage = imageHandleUtil.mergeImage(picImage, couponImage, taoBaoQRCode.getTitle(), taoBaoQRCode.getReservePrice(), taoBaoQRCode.getZkFinalPrice()); response.setContentType("image/jpg"); os = response.getOutputStream(); ImageIO.write(modifyImage, "jpg", os); os.flush(); } catch (Exception e) { LOGGER.error("getTaoBaoqQRCode error"); e.printStackTrace(); } finally { buffin.close(); os.close(); } }
二維碼QrCodeUtil 生成幫助類
public class QrCodeUtil { private static final int DAFAULT_WIDTH = 360; private static final int DAFAULT_HEIGHT = 360; private static final Logger LOGGER = LoggerFactory.getLogger(QrCodeUtil.class); public static String createQrCode(String text) { return createQrCode(DAFAULT_WIDTH, DAFAULT_HEIGHT, text); } public static String createQrCode(int widht, int height, String text) { HashMap<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); try { byte[] bytes = createQrCode2Bytes(widht, height, text); String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".png"; return UpYunClient.upload(fileName, bytes); } catch (Exception e) { LOGGER.error("create qrcode error", e); } return null; } public static byte[] createQrCode2Bytes(String text) { return createQrCode2Bytes(DAFAULT_WIDTH, DAFAULT_HEIGHT, text); } public static byte[] createQrCode2Bytes(int widht, int height, String text) { HashMap<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, widht, height, hints); ByteArrayOutputStream out = new ByteArrayOutputStream(); BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); ImageIO.write(image, "png", out); return out.toByteArray(); } catch (Exception e) { LOGGER.error("create qrcode error", e); } return null; } /** * 生成條形碼并已字節(jié)碼形式返回,生成的圖片格式為png * * @param contents * @param width * @param height * @return */ public static byte[] createBarcode2Byte(String contents, int width, int height) { int codeWidth = 3 + // start guard (7 * 6) + // left bars 5 + // middle guard (7 * 6) + // right bars 3; // end guard codeWidth = Math.max(codeWidth, width); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.CODE_128, codeWidth, height, null); BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(image, "png", out); return out.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return null; } }
二維碼生成我這里用的是谷歌的看下面maven pom.xml 文件
<!-- 條形碼、二維碼生成 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>2.2</version> </dependency>
合成圖片方法如何
package com.qft.campuscircle.common.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.URL; import javax.imageio.ImageIO; import org.springframework.stereotype.Component; @Component public class ImageHandleUtil { private Font font = null; private Graphics2D g = null; /** * 導(dǎo)入本地圖片到緩沖區(qū) * * @param imgName * @return */ public BufferedImage loadImageLocal(String imgName) { try { return ImageIO.read(new File(imgName)); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 導(dǎo)入網(wǎng)絡(luò)圖片到緩沖區(qū) * * @param imgName * @return */ public BufferedImage loadImageUrl(String imgName) { try { URL url = new URL(imgName); return ImageIO.read(url); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 生成新圖片到本地 * * @param newImage * @param img */ public void writeImageLocal(String newImage, BufferedImage img) { if (newImage != null && img != null) { try { // 目錄不存在則創(chuàng)建 String dirUrl = newImage.substring(0, newImage.lastIndexOf(File.separator)); File dir = new File(dirUrl); if (!dir.exists()) { dir.mkdirs(); } File outputfile = new File(newImage); ImageIO.write(img, "png", outputfile); } catch (IOException e) { e.printStackTrace(); } } } /** * 設(shè)定文字的字體等 * * @param fontStyle * @param fontSize */ public void setFont(String name, int style, int fontSize) { this.font = new Font(name, style, fontSize); } /** * 修改圖片,返回修改后的圖片緩沖區(qū)(只輸出一行文本),圖片居中顯示 * * @param img * @param content * @param y * @param color * @return */ public BufferedImage modifyImage(BufferedImage img, Object content, int y, Color color) { try { g = img.createGraphics(); g.setBackground(Color.WHITE); g.setColor(color);// 設(shè)置字體顏色 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 抗鋸齒 if (this.font != null) g.setFont(this.font); int width = img.getWidth();// 圖片寬度 if (content != null) { String str = content.toString(); int strWidth = g.getFontMetrics().stringWidth(str);// 字體寬度 g.drawString(str, (width - strWidth) / 2, y); } g.dispose(); } catch (Exception e) { e.printStackTrace(); } return img; } public BufferedImage modifyImage(BufferedImage img, Object content, int x, int y, Color color) { try { g = img.createGraphics(); g.setBackground(Color.WHITE); g.setColor(color);// 設(shè)置字體顏色 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 抗鋸齒 if (this.font != null) g.setFont(this.font); if (content != null) { String str = content.toString(); g.drawString(str, x, y); } g.dispose(); } catch (Exception e) { e.printStackTrace(); } return img; } /** * 將一張圖片畫在另一張圖片上 * * @param addImage 被添加的圖片 * @param sourceImg 源圖 * @param x * @param y * @param width * @param height * @return */ public BufferedImage modifyImagetogeter(BufferedImage addImage, BufferedImage sourceImg, int x, int y) { int width = addImage.getWidth(); int height = addImage.getHeight(); try { g = sourceImg.createGraphics(); g.drawImage(addImage, x, y, width, height, null); g.dispose(); } catch (Exception e) { e.printStackTrace(); } return sourceImg; } /** * * @param img1 * @param img2 * @param title 標(biāo)題 * @param reservePrice 現(xiàn)價(jià) * @param zkFinalPrice 折扣價(jià) * @return BufferedImage * @throws IOException */ public BufferedImage mergeImage(BufferedImage img1, BufferedImage img2,String title,String reservePrice,String zkFinalPrice) throws IOException { Font font = new Font("微軟雅黑", Font.BOLD, 20); int w1 = img1.getWidth(); int h1 = img1.getHeight(); int w2 = img2.getWidth(); int h2 = img2.getHeight(); BufferedImage newImage = new BufferedImage(w1, h2 + h1 + h2/2, BufferedImage.TYPE_INT_RGB);// 新的圖 Graphics2D graphics = (Graphics2D) newImage.getGraphics(); graphics.setBackground(Color.WHITE); graphics.fillRect(0, 0, newImage.getWidth(), newImage.getHeight()); graphics.drawImage(img1, 0, 0, null); graphics.drawImage(img2, (newImage.getWidth()) / 2 - (w2 / 2), newImage.getHeight() - h2, null); graphics.setFont(font); graphics.setColor(Color.BLACK); int width = graphics.getFontMetrics(font).stringWidth(title); int startY = h1 + 30; if (width > newImage.getWidth()) { char[] array = title.toCharArray(); StringBuilder sb = new StringBuilder(array[0]); for (char c : array) { sb.append(c); int newWidth = graphics.getFontMetrics(font).stringWidth(sb.toString()); if ((newWidth + 19) >= newImage.getWidth()) {// 準(zhǔn)備換行 graphics.drawString(sb.toString(), 0, startY); startY += 30; sb.delete(0, sb.length()); } } graphics.drawString(sb.toString(), 0, startY); } else { graphics.drawString(title, 0, startY); } graphics.drawString("現(xiàn)價(jià)¥"+reservePrice, 0, startY + 30); startY += 30; graphics.drawString("卷后價(jià)¥"+zkFinalPrice, 0, startY + 30); return newImage; } }
兩個(gè)幫助類里面有很多方法沒用到,大家只要看幾個(gè)關(guān)鍵的方法就可以了,TaoBaoQRCode 對(duì)象里面的屬性我就沒列出來了,大家自己根據(jù)自己的需求而定
以上就是java 實(shí)現(xiàn)圖片合成,并添加文字的詳細(xì)內(nèi)容,更多關(guān)于Java 圖片合成的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用java實(shí)現(xiàn)http多線程斷點(diǎn)下載文件(二)
下載工具我想沒有幾個(gè)人不會(huì)用的吧,前段時(shí)間比較無聊,花了點(diǎn)時(shí)間用java寫了個(gè)簡單的http多線程下載程序,我實(shí)現(xiàn)的這個(gè)http下載工具功能很簡單,就是一個(gè)多線程以及一個(gè)斷點(diǎn)恢復(fù),當(dāng)然下載是必不可少的,需要的朋友可以參考下2012-12-12Java中HashMap與String字符串互轉(zhuǎn)的問題解決
本文介紹了Java中HashMap與String字符串互轉(zhuǎn)的問題解決,當(dāng)我們有需求將HashMap轉(zhuǎn)為Json格式的String時(shí),需要使用FastJson/Gson將HashMap轉(zhuǎn)為String,感興趣的可以了解一下2022-03-03sqlserver和java將resultSet中的記錄轉(zhuǎn)換為學(xué)生對(duì)象
這篇文章主要介紹了如何利用sqlserver和java將resultSet中的記錄轉(zhuǎn)換為學(xué)生對(duì)象,附有超詳細(xì)的代碼,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12深入理解spring boot異步調(diào)用方式@Async
Spring為任務(wù)調(diào)度與異步方法執(zhí)行提供了注解支持。通過在方法上設(shè)置@Async注解,可使得方法被異步調(diào)用。下面這篇文章主要給大家介紹了關(guān)于spring boot異步調(diào)用方式@Async的相關(guān)資料,需要的朋友可以參考下。2017-07-07ssm框架下web項(xiàng)目,web.xml配置文件的作用(詳解)
下面小編就為大家?guī)硪黄猻sm框架下web項(xiàng)目,web.xml配置文件的作用(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10SpringBoot整合Shiro框架,實(shí)現(xiàn)用戶權(quán)限管理
Apache Shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼和會(huì)話管理。作為一款安全框架Shiro的設(shè)計(jì)相當(dāng)巧妙。Shiro的應(yīng)用不依賴任何容器,它不僅可以在JavaEE下使用,還可以應(yīng)用在JavaSE環(huán)境中。2021-06-06Java之Pattern.compile函數(shù)用法詳解
這篇文章主要介紹了Java之Pattern.compile函數(shù)用法詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08