本编文章主要是分享一下,从远程获取图片文件,用java在图片上写文字并合成图片的示例。一下代码完全拷贝后是可以正常运行的。

主要有三个类:

DrawPicFromUrlToOSS:核心类,获取图片并在图片上书写文字。

FontText:字体内容及样式类。

VerifyCodeUtils:对本文讲解的核心功能没多大用,和核心代码没多大关系,只是作者测试的时候使用的这个类的类加载器加载字体文件(*.fft)为输入流的一个类。并且这个功能一般是在服务器上没有安装字体库的时候才这样使用。作者主要是记录一下这个文件,这个文件是图形验证码的一个util。总之,可以忽略这个类。

如果是在springboot项目中要加载指定的字体,如SourceHanSansCN-Medium.ttf加载这个字体文件,注意pom文件中的resource和plugin配置。以下附有代码。

以下为代码:

package com.jll.read.file.read.remote;import com.jll.read.file.read.image.fonttext.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;/*** @Description 远程拉取图片并在图片上写文字* @Author: jinglonglong* @Date:2021-7-15**/
@Slf4j
public class DrawPicFromUrlToOSS {public static void main(String[] args) throws UnsupportedEncodingException {DrawPicFromUrlToOSS d = new DrawPicFromUrlToOSS();FontText text = new FontText();text.setText("你好,欢迎访问中秋图片!");text.setText2("中秋节快乐!");text.setText_color("#FF4040");text.setText_size(50);BufferedImage bimage = d.drawTextInRemoteImg("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F16%2F07%2F06%2F17577cd55945262.jpg%21r650&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628933927&t=25af9b7a5f461f17c14ade7651ba0daa",text);d.writeFileToPath(bimage,"D:\\image\\123.jpg");System.out.println("执行结束");}//bimage写到指定路径磁盘上public void writeFileToPath(BufferedImage bimage,String outPath){try {FileOutputStream out = new FileOutputStream(outPath);ImageIO.write(bimage, "JPEG", out);out.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** 在远程图片上写字** @param filePath 远程地址路径* @param text     字体格式*/public BufferedImage drawTextInRemoteImg(String filePath, FontText text) throws UnsupportedEncodingException {//这一步可以不需要,自定义实现,可以返回null。
//        Font fontSelf = getFont(text);Font fontSelf = null;//获取远程图片,给定一个url获取到图片后再处理BufferedImage img = getBufferedImageDestUrl(filePath);//图片宽度int imgWidth = img.getWidth(null);//图片高度int height = img.getHeight(null);//创建BufferedImage对象BufferedImage bimage = new BufferedImage(imgWidth, height,BufferedImage.TYPE_INT_RGB);//java.awt组件创建图形Graphics2D g = bimage.createGraphics();//设置图形g.setColor(getColor(text.getText_color()));g.setBackground(Color.white);g.drawImage(img, 0, 0, null);//字体Font font;if (null != fontSelf) {font = fontSelf;} else if (!StringUtils.isEmpty(text.getText_font())&& text.getText_size() != null) {font = new Font(text.getText_font(), Font.BOLD,text.getText_size());} else {font = new Font(null, Font.BOLD, 15);}//给图形设置字体g.setFont(font);// 计算文字长度,计算居中的x点坐标Graphics2D g2d = img.createGraphics();FontMetrics fm = g2d.getFontMetrics(font);//设置文本宽高setFontContent(g, fm, text, imgWidth);g.dispose();return bimage;}//加载字体对象public Font getFont(FontText text) {Font font = loadFont(text.getText_font(), text.getText_size(), Font.PLAIN);return font;}//设置文本宽高public void setFontContent(Graphics2D g, FontMetrics fm, FontText text, int imgWidth) throws UnsupportedEncodingException {String userName = new String(text.getText().getBytes("UTF-8"), "UTF-8");String userCode = new String(text.getText2().getBytes("UTF-8"), "UTF-8");log.info("### drawString-textStr:{}", userName);g.drawString(userName, 65, 180);int text2Width = (imgWidth - fm.stringWidth(text.getText2())) / 2;g.drawString(userCode, text2Width, 420);}/*** 远程图片转BufferedImage** @param destUrl 远程图片地址* @return*/public static BufferedImage getBufferedImageDestUrl(String destUrl) {HttpURLConnection conn = null;BufferedImage image = null;try {URL url = new URL(destUrl);conn = (HttpURLConnection) url.openConnection();if (conn.getResponseCode() == 200) {image = ImageIO.read(conn.getInputStream());return image;}} catch (Exception e) {e.printStackTrace();} finally {conn.disconnect();}return image;}/*** 加载字体,linux服务器上如果没有安装字体库,防止中文乱码,通过以下方法加载字体为InputStream,* 再通过Font.createFont(Font.TRUETYPE_FONT, resourceAsStream);生成字体对象Font,这样即使服务器没有安装* 字体库,也不会造成中文写到图片上乱码。* 如果springboot项目,字体文件*.fft文件要放到resources目录下。并且注意pom文件中的resource和plugin配置** @param fontFileName 字体文件* @param fontSize     字体大小* @return 字体*/public static Font loadFont(String fontFileName, int fontSize, int fontStyle) {//第一个参数是外部字体名,第二个是字体大小try {log.info("### fontFileName :{}", fontFileName);InputStream resourceAsStream = VerifyCodeUtils.class.getClassLoader().getResourceAsStream(fontFileName);log.info("### resourceAsStream :{}", resourceAsStream);Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, resourceAsStream);Font dynamicFontPt = dynamicFont.deriveFont(fontStyle, fontSize);log.info("### fontSize :{}", fontSize);resourceAsStream.close();return dynamicFontPt;} catch (Exception e) {log.error("### loadFont-exception:", e);//异常处理return new Font("宋体", Font.ITALIC, (int) fontSize);}}// 创建color对象public static Color getColor(String color) {if (color.charAt(0) == '#') {color = color.substring(1);}if (color.length() != 6) {return null;}try {int r = Integer.parseInt(color.substring(0, 2), 16);int g = Integer.parseInt(color.substring(2, 4), 16);int b = Integer.parseInt(color.substring(4), 16);return new Color(r, g, b);} catch (NumberFormatException nfe) {return null;}}
}
package com.jll.read.file.read.remote;import lombok.AllArgsConstructor;
import lombok.Data;/*** @Description 自定义的文本内容及文本样式对象* @Author: jinglonglong* @Date:2021-5-24**/
@Data
public class FontText {//文本内容1private String text;//文本内容2private String text2;private int text_pos;private String text_color;private Integer text_size;private String text_font;//字体  “黑体,Arial”public FontText(String text, int text_pos, String text_color,Integer text_size, String text_font) {super();this.text = text;this.text_pos = text_pos;this.text_color = text_color;this.text_size = text_size;this.text_font = text_font;}public FontText(String text, String text2, int text_pos, String text_color,Integer text_size, String text_font) {super();this.text = text;this.text2 = text2;this.text_pos = text_pos;this.text_color = text_color;this.text_size = text_size;this.text_font = text_font;}public FontText() {}
}
package com.jll.read.file.utils;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Random;/*** 字符源生成验证码* 此代码没多大作用,加载上述代码中字体流的时候可以使用其它类。不需要这个类,只是本地测试使用的是 *这个类,并且这个类是一个生成验证码的utils类,以此作为笔记。切记,此类与上述代码关系很小,基本没 *用。*/
public class VerifyCodeUtils {/*** 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符*/public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";// 随机数private static final Random random = new Random();// 字体private static final Font defaultFont = loadFont(VerifyCodeUtils.class.getResource("SourceHanSansCN-Medium.ttf").getFile(), 14);/*** 使用系统默认字符源生成验证码** @param verifySize 验证码长度* @return 验证码*/public static String generateVerifyCode(int verifySize) {return generateVerifyCode(verifySize, VERIFY_CODES);}/*** 使用指定源生成验证码** @param verifySize 验证码长度* @param sources    验证码字符源* @return 验证码*/public static String generateVerifyCode(int verifySize, String sources) {if (sources == null || sources.length() == 0) {sources = VERIFY_CODES;}// 根据元int codesLen = sources.length();Random rand = new Random(System.currentTimeMillis());StringBuilder verifyCode = new StringBuilder(verifySize);for (int i = 0; i < verifySize; i++) {verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));}return verifyCode.toString();}/*** 生成随机验证码文件,并返回验证码值** @param w          宽度* @param h          高度* @param outputFile 输出图片到文件* @param verifySize 验证码长度* @return 验证码字符串*/public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(w, h, outputFile, verifyCode);return verifyCode;}/*** 输出随机验证码图片流,并返回验证码值** @param w          宽度* @param h          高度* @param os         输出图片到流* @param verifySize 验证码长度* @return 验证码字符串*/public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(w, h, os, verifyCode);return verifyCode;}/*** 生成指定验证码图像文件*/public static void outputImage(int w, int h, File outputFile, String code) throws IOException {if (outputFile == null) {return;}// 先创建父文件夹File dir = outputFile.getParentFile();if (!dir.exists()) {boolean res = dir.mkdirs();}try {// 创建文件boolean res = outputFile.createNewFile();FileOutputStream fos = new FileOutputStream(outputFile);outputImage(w, h, fos, code);fos.close();} catch (IOException e) {throw e;}}/*** 输出指定验证码图片流*/public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {int verifySize = code.length();BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);Random rand = new Random();Graphics2D g2 = image.createGraphics();g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);Color[] colors = new Color[5];Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN,Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,Color.PINK, Color.YELLOW};float[] fractions = new float[colors.length];for (int i = 0; i < colors.length; i++) {colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];fractions[i] = rand.nextFloat();}Arrays.sort(fractions);g2.setColor(Color.GRAY);// 设置边框色g2.fillRect(0, 0, w, h);Color c = getRandColor(200, 250);g2.setColor(c);// 设置背景色g2.fillRect(0, 2, w, h - 4);//绘制干扰线Random random = new Random();g2.setColor(getRandColor(160, 200));// 设置线条的颜色for (int i = 0; i < 20; i++) {int x = random.nextInt(w - 1);int y = random.nextInt(h - 1);int xl = random.nextInt(6) + 1;int yl = random.nextInt(12) + 1;g2.drawLine(x, y, x + xl + 40, y + yl + 20);}// 添加噪点float yawpRate = 0.05f;// 噪声率int area = (int) (yawpRate * w * h);for (int i = 0; i < area; i++) {int x = random.nextInt(w);int y = random.nextInt(h);int rgb = getRandomIntColor();image.setRGB(x, y, rgb);}shear(g2, w, h, c);// 使图片扭曲g2.setColor(getRandColor(100, 160));int fontSize = h - 4;// Algerian字体// Font font = new Font("Algerian", Font.ITALIC, fontSize);Font font = defaultFont.deriveFont(Float.parseFloat(fontSize + ""));
//        Font font = new Font("宋体", Font.ITALIC, fontSize);g2.setFont(font);char[] chars = code.toCharArray();for (int i = 0; i < verifySize; i++) {AffineTransform affine = new AffineTransform();affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);g2.setTransform(affine);g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);}g2.dispose();ImageIO.write(image, "jpg", os);}/*** 加载字体** @param fontFileName 字体文件* @param fontSize     字体大小* @return 字体*/public static Font loadFont(String fontFileName, final float fontSize) {//第一个参数是外部字体名,第二个是字体大小try {File file = new File(fontFileName);FileInputStream fontStream = new FileInputStream(file);Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, fontStream);Font dynamicFontPt = dynamicFont.deriveFont(fontSize).deriveFont(Font.ITALIC);fontStream.close();return dynamicFontPt;} catch (Exception e) {//异常处理return new Font("宋体", Font.ITALIC, (int) fontSize);}}/*** 获取随机颜色*/private static Color getRandColor(int fc, int bc) {if (fc > 255)fc = 255;if (bc > 255)bc = 255;int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}/*** 获取随机颜色*/private static int getRandomIntColor() {int[] rgb = getRandomRgb();int color = 0;for (int c : rgb) {color = color << 8;color = color | c;}return color;}/*** 获取随机rgb*/private static int[] getRandomRgb() {int[] rgb = new int[3];for (int i = 0; i < 3; i++) {rgb[i] = random.nextInt(255);}return rgb;}/*** 剪切*/private static void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}/*** 绘制纵向线*/private static void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);// boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}/*** 绘制横向线*/private static void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(40) + 10; // 50;// boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}// ================================================================// Test Methods// ================================================================public static void main(String[] args) throws IOException {VerifyCodeUtils.outputImage(300, 100,new File("/Users/zeyuphoenix/Documents/11.png"), "ABcJ");}
}

springboot项目时,如果公司linux上没有安装字体库,为了防止中文乱码,一般需要加载指定的字体库文件为输入流,如 SourceHanSansCN-Medium.ttf 这个字体文件,然后按照上面代码加载为InputStream使用,这样能防止部署到服务器后,运行此功能生成中文乱码,pom需要如下配置,才能保证 *.ttl 文件被打包到jar包中。*.ttl 文件一般需要放在resources目录下。

<build><finalName>${project.artifactId}</finalName><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource><!-- maven的resource插件开启filtering功能后,会破坏有二进制内容的文件 --><resource><directory>${project.basedir}/src/main/java</directory><includes><include>**/*.ttf</include><include>**/*.png</include></includes></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><nonFilteredFileExtensions><nonFilteredFileExtension>ttf</nonFilteredFileExtension><nonFilteredFileExtension>xlsx</nonFilteredFileExtension><nonFilteredFileExtension>xls</nonFilteredFileExtension><nonFilteredFileExtension>zip</nonFilteredFileExtension><nonFilteredFileExtension>cer</nonFilteredFileExtension><nonFilteredFileExtension>pfx</nonFilteredFileExtension><nonFilteredFileExtension>py</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin></plugins></build>

java获取远程图片并在图片上写文字相关推荐

  1. java解压服务器文件夹,java获取远程服务器上的文件夹

    java获取远程服务器上的文件夹 内容精选 换一换 安装X722板载网卡驱动软件包,使裸金属服务器支持在v5服务器上下发.其他类型服务器可跳过此步骤.本文以Windows Server 2016为例, ...

  2. java 获取服务器上文件,java获取远程服务器上的文件

    java获取远程服务器上的文件 内容精选 换一换 已成功登录Java性能分析.待安装Guardian的服务器已开启sshd.待安装Guardian的服务器已安装JRE,JRE版本要求为Huawei J ...

  3. java 获取gif帧数_Java图片处理之获取gif图一帧图片的两种方法

    前言 本文主要给大家介绍了关于Java获取gif图一帧图片的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.Java原生代码实现gif获取一帧图片 先看测试代码: pu ...

  4. java绘制海报,使用BufferedImage,Graphics2D,drawString方法在图片上写文字,中文不显示;drawString写文字为空问题

    项目场景: 项目场景:公司需要制作一张海报.通过java后台制作海报,给图片拼接图片,添加水印添加文字,定义字体为"宋体",给海报添加头像.姓名.性别.个人简介.二维码等信息.把代 ...

  5. java怎么获取服务器文件夹,java获取远程服务器的文件夹

    java获取远程服务器的文件夹 内容精选 换一换 工具中所有涉及上传文件功能的,如果需要上传的文件大于1GB或者解压后超过剩余磁盘空间的一半,则需要释放磁盘空间或手动将文件上传至服务器,其他情况可通过 ...

  6. php 用gd库在图片上写文字,并处理文字糊模问题

    今天有个需求,用php在一张图片上写文字. 这个不是挺简单的嘛?我在一个test.php文件上,敲出6行代码,搞定 img=imagecreatefrompng("C:\Users\Admi ...

  7. 使用Qpaint在图片上写文字

    开发过程中需要实现在图片上叠加文字,可以采用Qpaint在图片上写文字,然后将图片显示在上面.再将Qlabel加到Qwidget中.效果如下 //创建对象,加载图片 QPixmap pix; pix. ...

  8. java获取远程服务器目录,在远程服务器创建三级目录

    java获取远程服务器目录,在远程服务器创建三级目录 1.添加依赖 <dependency><groupId>com.jcraft</groupId><art ...

  9. 在Linux中使用Graphics、drawString在图片上写文字时,中文问题

    在Linux中使用Graphics.drawString在图片上写文字时,中文写不出.乱码问题 主要因为Linux没有包含所需字体 1.先下载所需字体 2.将字体.ttc文件放到/usr/share/ ...

最新文章

  1. python socket server库_python基础之socket与socketserver
  2. 数据结构 - 反转单链表(C++)
  3. cenotos 卸载mysql_CentOS 6.2编译安装Nginx1.0.12+MySQL5.5.21+PHP5.3.10 | 系统运维
  4. rsatool使用步骤图解_图解360系统重装大师如何使用
  5. 找高清壁纸,没有那么麻烦,高图网帮你搞定!
  6. 计算机专业学生创新创优创业情况,高校计算机专业学生创新创业教育模式研究...
  7. Java Hello World程序
  8. Day11 - 使用正则表达式
  9. 如何做实时监控?—— 参考 Spring Boot 实现
  10. java开发学历要求_学Java开发有学历限制要求吗?
  11. Ubuntu入门——基础终端命令
  12. 多空对比:一个实用的短中长期资金观察指标介绍
  13. 【Proteus仿真】51单片机+DAC0832+LCD1602制作LM317数控直流电源
  14. 一家麻辣烫店如何实现月净利五万
  15. 泰坦尼克号数据_数据分析实战3:泰坦尼克号生存分析
  16. 数据分析基础-假设检验原理详解
  17. ios手机怎么连接adb命令_Mac ADB 命令连接 android手机并进行各种操作
  18. 一个亿万富翁的创业自述
  19. pytorch——基础
  20. 干货|认识kata-containers

热门文章

  1. 电脑怎么安装免费的office
  2. 2021-06-27 记录最近刷过的数论题(整除分块,MillerRabin素性检测,积性函数,重数)
  3. ORB-SLAM 2 整理
  4. 哈希表(Hash Table)及散列法(Hashing)
  5. 计算请假工时,去除周六周末的时间
  6. 给青海玉树捐款账号是什么--百度快照查看
  7. 审美--《艺术与审美》课程学习笔记
  8. 初识Btrfs文件系统
  9. 语音论文中英语的高级表达(持续更新ing...)
  10. mysql千分位,数字转换千分位展示的方法及保留固定小数位的方法toLoacleString()方法详解...