java给图片添加文字的时候保持印章在最上层

2023-09-21 09:58:42

比如生成证书的时候,可能模板图片里面已经有印章了,我们如何把文字添加上去后再把印章盖回去呢?
可以通过操纵像素点来完成

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public class WithLayersBufferedImage {

    private BufferedImage image;
    private Graphics2D graphics2D;


    public WithLayersBufferedImage(InputStream inputStream) throws IOException {
        image = ImageIO.read(inputStream);
        graphics2D = bufferedImage.createGraphics();
    }

    /**
     * 调整尺寸.
     *
     */
    public void reSize(int width, int height) {
        BufferedImage outputImage = new BufferedImage(width, height, image.getType());
        Graphics2D graphics = bufferedImage.createGraphics();
        graphics.drawImage(image, 0, 0, width, height, null);

        this.image = outputImage;
        this.graphics2D = graphics;
    }

    /**
     * 写证书文字 默认黑体 加粗.
     */
    public void writeFont(int x, int y, String str, int size) {
        Font font = getSimHeiFont(size);
        this.graphics2D.setFont(font);
        this.graphics2D.setColor(Color.BLACK);
        String s = new String(str.getBytes(Charset.forName("UTF-8")), Charset.forName("UTF-8"));
        this.graphics2D.drawString(s, x, y);
    }


    /**
     * 保持印章在上层.
     *
     * @param minX         the min x 要保持图层最上层的区域坐标,区域越小需要遍历的像素点越少
     * @param maxX         the max x 要保持图层最上层的区域坐标,区域越小需要遍历的像素点越少
     * @param minY         the min y 要保持图层最上层的区域坐标,区域越小需要遍历的像素点越少
     * @param maxY         the max y 要保持图层最上层的区域坐标,区域越小需要遍历的像素点越少
     * @param judgeRedFunc 判断方法,判断哪些像素点是要保持上层的,对于印章来说就是红色的像素,传null就行,其他的自行写判断方法
     * @param consumer     实际的图片操作
     */
    public void KeepSealOnUpper(int minX, int maxX, int minY, int maxY, Function<Color, Boolean> judgeRedFunc, Consumer<WithLayersBufferedImage> consumer) {

        if (judgeRedFunc == null) {
            //如果是红色 就存起来 这里比较粗暴的判断三色原里,红色大于200 其他二色小于100就算印章的颜色(如果自己模板图片的颜色非常相近则需要好好调节)
            judgeRedFunc = color -> color.getRed() > 200 && color.getGreen() < 100 && color.getBlue() < 100;
        }
		
		//先把这区域内符合的像素点都保存起来
        List<int[]> l = new ArrayList<>();
        for (int w = minX; w <= maxX; w++) {
            for (int h = minY; h <= maxY; h++) {
                int pixel = image.getRGB(w, h);
                Color color = new Color(pixel);
                if (judgeRedFunc.apply(color)) {
                    l.add(new int[]{w, h, pixel});
                }
            }
        }
		//执行画图操作 可以写文字或画图片之类
        consumer.accept(this);

		//重新覆盖像素点回去
        for (int[] a : l) {
            int pixel = image.getRGB(a[0], a[1]);
			
			//有变化
            if (pixel != a[2]) {
                //红色被人覆盖了
                Color color = new Color(a[2]);
                Color c = new Color(color.getRed(), color.getGreen(), color.getBlue(), 200);//设置点透明度,这样更真实
                image.setRGB(a[0], a[1], c.getRGB());
            }
        }

    }

    /**
     * 写出.
     *
     * @param format       jpeg png
     * @param outputStream the output stream
     * @throws IOException the io exception
     */
    public void output(String format, OutputStream outputStream) throws IOException {
        graphics2D.dispose();
        ImageIO.write(image, format, outputStream);
    }

}

使用

public class Test{
	public void main(String[] args){
		
        InputStream inputStream = new ByteArrayInputStream(fileContent);
        WithLayersBufferedImage  ci = new WithLayersBufferedImage (inputStream);
        ci.reSize(1000, 800);
		
		ci.writeFont(200, 400,"xxxxxx", 30);
		
		ci.writeFont(900, 300, "xxxxxx", 34);

		
		ci.writeFont(300, 400, "xxxxxx", 50);

		//设置证书日期
		ci.KeepSealOnUpper(800, 1000, 700, 750, null, (s) -> {
			s.writeFont(850, 730, "xxxx年xx月xx日", 30);
		});


        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ci.output(imageType, os);
		
	}
}

同理,这稍加改造也可以用于分离图层等操作

更多推荐

Elasticsearch 快速开始

Elasticsearch是一个分布式的RESTful风格的搜索和数据分析引擎。查询:Elasticsearch允许执行和合并多种类型的搜索—结构化、非结构化、地理位置、度量指标—搜索方式随心而变。分析:找到与查询最匹配的十个文档是一回事。但是如果面对的是十亿行日志,又该如何解读呢?Elasticsearch聚合让您能

AIGC生态,引领社会、行业、个体的翻天覆地变革

1879年,当爱迪生成功地实验出能够持续发光的灯丝时,他迎来了一个新的挑战:如何让更多人能够享受到电力的便利?经过艰难探索,直到1882年9月,在曼哈顿的珍珠街上,爱迪生才铺设了世界上第一张电力网络,为普罗大众提供了电力。正由此,第二次工业革命的幕布才得以徐徐打开。每当一项重大技术突破出现时,人类都不得不思考如何将其普

MT6785(Helio G95)安卓核心板_联发科4G高能低耗安卓主板开发板

MTK6785(HelioG95)安卓核心板采用八核CPU具有两个强大的ArmCortex-A76处理器内核,主频高达2.05GHz,外加六个Cortex-A55高效处理器。其强大的图形性能由ArmMali-G76MC4提供,速度可提升至900MHz。高达10GB的2133MHz的LPDDR4X提供了充足的带宽,同时支

HarmonyOS开发:那些开发中常见的问题汇总(一)

前言本来这篇文章需要讲述静态共享包如何实现远程依赖和上传以及关于静态共享包私服的搭建,非常遗憾的告诉大家,由于组织管理申请迟迟未通过,和部分文档官方权限暂未开放,关于这方面的讲解需要延后了,大概需要等到2024年第一季度,也就是来年,毕竟关于HarmonyOS的升级,舍弃AOSP,也是在2024年第一季度才会面向所有开

【HarmonyOS】元服务卡片router实现跳转到指定页面

【关键字】元服务卡片、router跳转不同页面【写在前面】本篇文章主要介绍开发元服务卡片时,如何实现从卡片中点击事件跳转到指定的应用内页面功能。此处以JSUI开发服务卡片为例,JS卡片支持组件设置action,包括router事件和message事件,其中router事件用于应用跳转,message事件用于卡片开发人员

【鸿蒙(HarmonyOS)】UI开发的两种范式:ArkTS、JS(以登录界面开发为例进行对比)

文章目录一、引言1、开发环境2、整体架构图二、认识ArkUI1、基本概念2、开发范式(附:案例)(1)ArkTS(2)JS三、附件一、引言1、开发环境之后关于HarmonyOS技术的分享,将会持续使用到以下版本HarmonyOS:3.1/4.0SDK:API9ReleaseNode.js:v14.20.1DevEcoS

Zookeeper应用场景和底层设计

一、什么是zookeeperZookeeper是一个开源的分布式协调服务框架,它是服务于其它集群式框架的框架。【简言之】有一个服务A,以集群的方式提供服务。只需要A专注于它提供的服务就可以,至于它如何以多台服务器协同完成任务的事情,交给Zookeeper来协调。【底层设计逻辑】1)基于观察者设计模式2)等价于文件系统+

开源项目的版本管理:Git的最佳实践

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

【Rust 基础篇】Rust 模式:高效、安全和灵活的匹配工具

导言在编程中,经常需要对数据进行匹配和处理,例如从一个复杂的数据结构中提取特定的值,或者根据不同的情况执行不同的逻辑。Rust是一门现代的系统编程语言,它引入了一种称为"模式"(Pattern)的强大特性,使得数据的匹配和处理变得高效、安全和灵活。本篇博客将深入探讨Rust模式的各种用法,带您领略Rust的魅力。什么是

ES6如何声明一个类?类如何继承?

在JavaScript中,您可以使用关键字class来声明一个类。类是一种模板,用于创建对象的构造函数,其中包含了属性和方法。以下是声明一个类的基本语法:classClassName{constructor(){//构造函数,用于创建对象实例时初始化属性this.propertyName=value;}//方法定义me

stm32学习-芯片系列/选型

【03】STM32·HAL库开发-初识STM32|STM概念、芯片分类、命名规则、选型|STM32原理图设计、看数据手册、最小系统的组成、STM32IO分配_小浪宝宝的博客-CSDN博客STM32:ST是意法半导体,M是MCU/MPU,32是32位。ST累计推出了:5大类、18个系列、1000多个型号的Cortex内核

热文推荐