欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!

程序员文章站 2022-04-06 13:13:40
序言大学毕设做的是 游戏-QQ机器人查询工具,选择的国外super cell的游戏COC(也是因为国内的游戏生态不提供API接口,一般都被鹅厂、猪场"*"了,甚至super cell最近上线的荒野行动国服,也被鹅肠进行了掌控)。选择的QQ作为载体,所以很多大数据量的情况加就需要弃用文字,使用图片。那么使用图片就需要进行图片生成,所以开始在java.awt.* 的包下进行各种踩坑之旅。都是java处理图片,没有python优秀。但是既然选择了java,就要对他负责到底。java只是一门语言,优秀与否...

序言

大学毕设做的是 游戏-QQ机器人查询工具,选择的国外super cell的游戏COC(也是因为国内的游戏生态不提供API接口,一般都被鹅厂、猪场"*"了,甚至super cell最近上线的荒野行动国服,也被鹅肠进行了掌控)。
选择的QQ作为载体,所以很多大数据量的情况加就需要弃用文字,使用图片。那么使用图片就需要进行图片生成,所以开始在java.awt.* 的包下进行各种踩坑之旅。

都说java处理图片,没有python优秀。但是既然选择了java,就要对他负责到底。
java只是一门语言,优秀与否,还是取决去使用它的人!

  • 首先亮出两张java生成后的图片给大家看效果。
荐
                                                        java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!荐
                                                        java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!

这里并不完全都是代码生成的,模板是提前做好的!其目的也是为了减少代码的重复工作!

在开发过程中,使用BufferedImage遇到的问题,解决的和未解决的问题!

1.锯齿效果(已解决)

之前生成的图片,文字放大后完全不能看,被啃了一样,文字小的看了也别扭!

public static void main(String[] args) {
		try {
			BufferedImage image = new BufferedImage(800, 900, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = (Graphics2D)image.createGraphics();
			g.setFont(new Font("微软雅黑", Font.BOLD, 100));
			g.setColor(Color.white);
			g.drawString("文字测试", 60, 200);
			ImageIO.write(image, "png", new File("G:\\image\\test2.png"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

上面是正常情况下写的代码,但是生成的图片,文字和“狗啃了”差不多,于是在百度的了解下,加入代码!

g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);

完美解决!!!
荐
                                                        java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!


2.自定义文字颜色and文字字体(已解决)

在生成图片中,java自带的字体、颜色不够我们使用。

颜色的问题,Color类就自带的有使用RGB来进行绘色!

Color color = new Color(,绿,)

字体的问题,【后期以及全部用java自带的字体】
①首先贴出一段查询自己电脑可以使用那些文字,以及文字使用后效果的代码。直接复制运行即可。

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 javax.imageio.ImageIO;

public class ImageFont {
	private static String saveFile = "c://fontAll.png";
	public static void main(String[] args) {
		try {
			java.awt.GraphicsEnvironment eq = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment();
			String[] a = eq.getAvailableFontFamilyNames(); 
			
			BufferedImage image = new BufferedImage(1600, (a.length+2)*30 + 80, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = (Graphics2D)image.createGraphics();
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
			for (int i = 1; i < a.length+1; i++) {
				Font font = new Font(a[i-1],Font.CENTER_BASELINE,25);
				g.setFont(font);
				g.drawString(a[i-1], 10, 30*i);
				g.drawString("1234567890N一", 800, 30*i);
			}
			ImageIO.write(image, "png", new File(saveFile));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

②引入自定义字体
【经过测试,执行速度没有使用java自带的字体执行快】

这里就不引入代码了,我做了简单封装,可能大家并不适用,但是论坛有相关帖子java引入自定义字体的方法。直接食用。展示引入“包图小白体”后的效果图:荐
                                                        java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!

3.文字居中 自动换行的处理。(未完美处理)

g.drawString(内容,X, y);
  • 因为文字是根据文字内容,XY坐标从做往右进行排列,并不会进行居中,和自动换行操作
  • 自认为,换行处理没有处理的完美。 代码冗余,使用的substring分割的字符串。
  • 文字换行处理方式:
    分割字符串 --> 分割后循环遍历,增加y轴高度。

这里有个很严重的问题,就是 汉字 和 数字字母符号 长度不同,对于处理文字+数字的方式,界面极不友好美观,所以在处理字符串的时候将所有字符进行的全角处理!当然字体也会影响文字的大小!


  • 文本内容居中 代码如下
Font font=new Font("微软雅黑",Font.PLAIN,50);  
FontMetrics fontMetrics = g.getFontMetrics(Font);
int textWidth = fontMetrics .stringWidth(文本内容);
int X = (图片宽度 - textWidth) / 2;

是否居中一目了然,如下生成的文字居中图片

荐
                                                        java生成图片,自己踩过的那些坑。java.awt的学习笔记!!!

4.特殊文字处理,只显示方框(部分处理)

这个坑,确实难填。因为coc是一款全球游戏,覆盖了各国语言,所以很多种语言,或者符号,drawString 都是不认可的,所以只能在填入的text文本内容之前,对text进行处理了,这点没啥好说的,转换字符集。百度各种办法,但是用到对于特殊符号,最好的解决办法还是使用“Menlo”的的字体!!!

 Font font = new Font("Menlo", Font.BOLD, 120)

5.图片处理问题–压缩、水印、旋转、拼接

这里推荐Google的java开源 thumbnailator !!!

补充

1.关于获取网络图片

网络图片,通过HTTP获取图片,然后进行处理,或者拼接!


如下,httpsGet 方法,可获取HTTPS 需要进行SSL校验的请求,并获取返回的BufferedImage
HTTP获取的方法,网络有很多。其中只需要通过InputStream 流获取,然后通过ImageIO.read(InputStream);的方式将内容转换成BufferedImage供我们进行操作

  • 如下提供一个发送HTTPS请求的工具类,需要HttpClient工具 ,如下导入maven
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.7</version>
</dependency>

import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpUtils;

import org.apache.commons.collections.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Https {
	
	
	private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    /**
     * 定义类型,用于获取不同类型的httpclient
     */
    enum CLIENT_TYPE {
        HTTP, HTTPS
    }

    /**
     * https post请求
     *
     * @param url        请求地址
     * @param headerMap  请求头信息
     * @param contentMap 请求体信息
     * @return 结果返回
     */
    public static String httpsPost(String url, Map<String, String> headerMap, Map<String, String> contentMap) {
        return httpsPost(url, headerMap, contentMap, "UTF-8");
    }

    /**
     * http post请求
     *
     * @param url        请求地址
     * @param headerMap  请求头信息
     * @param contentMap 请求体信息
     * @return 结果返回
     */
    public static String httpPost(String url, Map<String, String> headerMap, Map<String, String> contentMap) {
        return httpPost(url, headerMap, contentMap, "UTF-8");
    }

    /**
     * https get请求
     *
     * @param url      请求地址
     * @param paramMap 请求参数
     * @return 结果返回
     */
    public static BufferedImage httpsGet(String url, Map<String, String> paramMap) {
        return httpsGet(url, paramMap, "UTF-8");
    }
    /**
     * https get请求
     *
     * @param url      请求地址
     * @param paramMap 请求参数
     * @return 结果返回
     */
    public static String httpsGetTxt(String url, Map<String, String> paramMap) {
        return httpsGetTxt(url, paramMap, "UTF-8");
    }

    /**
     * http get请求
     *
     * @param url      请求地址
     * @param paramMap 请求参数
     * @return 结果返回
     */
    public static BufferedImage httpGet(String url, Map<String, String> paramMap) {
        return httpGet(url, paramMap, "UTF-8");
    }

    /**
     * @param url        请求地址
     * @param headerMap  请求头信息
     * @param contentMap 请求体信息
     * @param charset    编码类型
     * @return 结果返回
     */
    public static String httpsPost(String url, Map<String, String> headerMap, Map<String, String> contentMap, String charset) {
        return post(url, headerMap, contentMap, charset, CLIENT_TYPE.HTTPS);
    }

    /**
     * @param url        请求地址
     * @param headerMap  请求头信息
     * @param contentMap 请求体信息
     * @param charset    编码类型
     * @return 结果返回
     */
    public static String httpPost(String url, Map<String, String> headerMap, Map<String, String> contentMap, String charset) {
        return post(url, headerMap, contentMap, charset, CLIENT_TYPE.HTTP);
    }

    /**
     * @param url      请求地址
     * @param paramMap 请求参数
     * @param charset  编码类型
     * @return 结果返回
     */
    public static BufferedImage httpsGet(String url, Map<String, String> paramMap, String charset) {
        return get(url, paramMap, charset, CLIENT_TYPE.HTTPS);
    }
    /**
     * @param url      请求地址
     * @param paramMap 请求参数
     * @param charset  编码类型
     * @return 结果返回
     */
    public static String httpsGetTxt(String url, Map<String, String> paramMap, String charset) {
        return getTxt(url, paramMap, charset, CLIENT_TYPE.HTTPS);
    }
    /**
     * @param url      请求地址
     * @param paramMap 请求参数
     * @param charset  编码类型
     * @return 结果返回
     */
    public static BufferedImage httpGet(String url, Map<String, String> paramMap, String charset) {
        return get(url, paramMap, charset, CLIENT_TYPE.HTTP);
    }

    /**
     * post 请求的实际方法
     *
     * @param url        请求地址
     * @param headerMap  请求头信息
     * @param contentMap 请求体信息
     * @param charset    编码类型
     * @param type       协议类型
     * @return 结果返回
     */
    private static String post(String url, Map<String, String> headerMap, Map<String, String> contentMap, String charset, CLIENT_TYPE type) {

        String result = null;
        HttpClient httpClient = null;
        try {
            HttpPost post = new HttpPost(url);
            if (MapUtils.isNotEmpty(headerMap)) {// 设置请求头
                for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                    post.addHeader(entry.getKey(), entry.getValue());
                }
            }

            if (MapUtils.isNotEmpty(contentMap)) {// 设置请求体
                List<NameValuePair> content = getNameValuePairList(contentMap);
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(content, charset);
                post.setEntity(entity);
            }

            httpClient = getClient(type);//这里是重点,根据不同协议获取不同类型的client端
            HttpResponse response = httpClient.execute(post);//发送请求并接收返回数据
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, charset);
                }
            }
            return result;
        } catch (Exception ex) {
            throw new RuntimeException("请求:" + url + " 异常:" + ex.getMessage());
        } finally {
            try {
                if (null != httpClient && null != httpClient.getConnectionManager()) {
                    httpClient.getConnectionManager().shutdown();
                }
            } catch (Exception e) {
                logger.error("请求:" + url + " 流关闭异常或者httpclient关闭异常");
            }
        }
    }

    /**
     * get 请求的实际方法
     *
     * @param url      请求地址
     * @param paramMap 请求参数
     * @param charset  编码类型
     * @param type     协议类型
     * @return 结果返回
     */
    private static BufferedImage get(String url, Map<String, String> paramMap, String charset, CLIENT_TYPE type) {

        HttpClient httpClient = null;
        try {
            if (MapUtils.isNotEmpty(paramMap)) {// 拼接参数
                // 设置请求体
                List<NameValuePair> content = getNameValuePairList(paramMap);
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(content, charset);
                String params = EntityUtils.toString(entity);
                url = url + "?" + params;
            }
            HttpGet get = new HttpGet(url);
            get.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36");
            get.addHeader("authorization", "Bearer"+BackEndHttpRequest.API);
            httpClient = getClient(type);
            RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) //连接超时时间
                    .setSocketTimeout(1000*10) //数据传输的超时时间
                    .build();
            get.setConfig(config);
            HttpResponse response = httpClient.execute(get);            //发送请求并接收返回数据
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                String value = resEntity.getContentType().getValue();
                System.out.println("返回图片为"+value);
                InputStream content = resEntity.getContent();
                BufferedImage image = ImageIO.read(content);
                return image;
            }
            return null;
        } catch (Exception ex) {
            throw new RuntimeException("请求:" + url + " 异常:" + ex.getMessage());
        } finally {
            try {
            	
            } catch (Exception e) {
                logger.error("请求:" + url + " 流关闭异常或者httpclient关闭异常");
            }
        }
    }
    /**
     * get 请求的实际方法
     *
     * @param url      请求地址
     * @param paramMap 请求参数
     * @param charset  编码类型
     * @param type     协议类型
     * @return 结果返回
     */
    private static String getTxt(String url, Map<String, String> paramMap, String charset, CLIENT_TYPE type) {
    	String result = "";
        HttpClient httpClient = null;
        try {
            if (MapUtils.isNotEmpty(paramMap)) {// 拼接参数
                // 设置请求体
                List<NameValuePair> content = getNameValuePairList(paramMap);
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(content, charset);
                String params = EntityUtils.toString(entity);
                url = url + "?" + params;
            }
            HttpGet get = new HttpGet(url);
            get.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36");
            get.addHeader("authorization", "Bearer"+BackEndHttpRequest.API);
            httpClient = getClient(type);
            RequestConfig config = RequestConfig.custom().setConnectTimeout(1000) //连接超时时间
                    .setSocketTimeout(1000*10) //数据传输的超时时间
                    .build();
            get.setConfig(config);
            HttpResponse response = httpClient.execute(get);            //发送请求并接收返回数据
            if (response != null) {
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, charset);
                }
                return result;
            }
            return null;
        } catch (Exception ex) {
            throw new RuntimeException("请求:" + url + " 异常:" + ex.getMessage());
        } finally {
            try {
            	
            } catch (Exception e) {
                logger.error("请求:" + url + " 流关闭异常或者httpclient关闭异常");
            }
        }
    }
    private static List<NameValuePair> getNameValuePairList(Map<String, String> paramMap) {
        List<NameValuePair> content = null;
        if (MapUtils.isNotEmpty(paramMap)) {
            // 设置请求体
            content = new ArrayList<NameValuePair>();
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                content.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        return content;
    }

    /**
     * 根据指定类型返回http、https类型的客户端
     *
     * @param type 类型
     * @return 客户端
     * @throws Exception 异常信息
     */
    private static DefaultHttpClient getClient(CLIENT_TYPE type) throws Exception {
        if (type == CLIENT_TYPE.HTTP) {//http类型
            return new DefaultHttpClient();
        } else if (type == CLIENT_TYPE.HTTPS) {//https类型
            return new SSLClient();
        } else {
            throw new RuntimeException("未知协议类型,请重新指定");
        }
    }

    /**
     * 自定义SSL client
     */
    static class SSLClient extends DefaultHttpClient {
        public SSLClient() throws Exception {
            super();
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            //传输协议需要根据自己的判断 
            //SSLContext ctx = SSLContext.getInstance("TLSv1.2");
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = this.getConnectionManager();
            SchemeRegistry sr = ccm.getSchemeRegistry();
            sr.register(new Scheme("https", 443, ssf));
        }
    }

    
}

2.获取HTML渲染后的图片!

这个比较复杂,用到的工具类挺多的,有时间我在慢慢写!

本文地址:https://blog.csdn.net/weixin_43754451/article/details/107317856