java 处理图片图片合成

最近写了一个java的图片合成相关的项目,真的是一踩一个坑,下面博主说说遇见的一些坑和怎么解决的这些问题。 本文主要讲图片合成,加文字还是比较简单的。

先讲下我的需求,把一张图片盖到另外一张图片上面,然后在图片上加上字

第一个版本

在这里插入图片描述

最开始的时候我用的是thumbnailator工具包,如上图效果

但是问题来了,这张图有很大的问题,两个图都是透明度发生了变化。

第二个版本

使用java自带的Graphics2D

代码如下

		String blackPath = "";
        String fontPath = "";
        
        // 水印图
        URL frontUrl = new URL(fontPath);
        // 地图
        URL blackUrl = new URL(blackPath);
        
        BufferedImage blackImage = ImageIO.read(blackUrl );
        BufferedImage frontImage = ImageIO.read(frontUrl );
        // 拉伸下
        Thumbnails.Builder<BufferedImage> of = Thumbnails.of(blackImage).size(750, 750);
        blackImage = of.asBufferedImage();
        Graphics2D g2d = blackImage.createGraphics();
        // 在地图上绘制水印
        g2d.drawImage(frontImage, 0, 0, 750, 750, null);
        g2d.dispose();

这个代码可以合成图片,但是有两个问题

  1. 图片失真
  2. 图片合成后在叠加的部分颜色发生了变化

第三个版本

使用Toolkit.getDefaultToolkit() 读取image

图片image转化为bufferImage方法

 		public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
        }

        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();

        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent Pixels
        //boolean hasAlpha = hasAlpha(image);

        // Create a buffered image with a format that's compatible with the screen
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;
       /* if (hasAlpha) {
         transparency = Transparency.BITMASK;
         }*/

            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(
                    image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }

        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            //int type = BufferedImage.TYPE_3BYTE_BGR;//by wang
        /*if (hasAlpha) {
         type = BufferedImage.TYPE_INT_ARGB;
         }*/
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }

        // Copy image to buffered image
        Graphics g = bimage.createGraphics();

        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bimage;
    }

图片合成方法

		String blackPath = "";
        String fontPath = "";

        // 水印图
        URL frontUrl = new URL(fontPath);
        // 地图
        URL blackUrl = new URL(blackPath);
        // 读取背景图
        Image blackImage = Toolkit.getDefaultToolkit().getImage(blackUrl);
        // 读取水印图
        Image frontImage = Toolkit.getDefaultToolkit().getImage(frontUrl);

        BufferedImage image = toBufferedImage(blackImage);
        // 拉伸下,
        Thumbnails.Builder<BufferedImage> of = Thumbnails.of(image).size(750, 750);
        image = of.asBufferedImage();
        Graphics2D g2d = image.createGraphics();
        // 在地图上绘制水印
        g2d.drawImage(frontImage, 0, 0, 750, 750, null);
        g2d.dispose();

改进之后图片的失真问题解决了, 图片的颜色变化问题也解决了。
但是新问题又来了,合成的时候有时候成功有时候失败

上面这个问题真的是日了狗了。

在这里抱怨一下,程序员不怕不成功的代码,就怕这代码有时候成功,有时候失败,最后我找到问题所在,这个读取image的方法它不是同步的,也就是说必须把它变成同步。

第四个版本

这个方法是把图片读取从异步变成同步


@Slf4j
public class MediaTrackerRunner extends Applet implements Runnable
{

    int speed = 5;

    private String path;

    public MediaTrackerRunner(String path) throws HeadlessException
    {
        this.path = path;
    }

    @Override
    public void init()
    {
        super.init();
    }


    @Override
    public void run()
    {

        while (true)
        {
            repaint(); // 重绘
            try
            {
                // 休眠,休眠时间根据图像显示速度计算
                Thread.sleep(1000 / speed);
            }
            catch (InterruptedException e)
            {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * [简要描述]:<br/> 根据图片路径读取图片, 同步
     * [详细描述]:<br/>

     * @return java.awt.Image
     * 2020/12/9 - 19:05
     **/
    public Image execute()
    {

        MediaTracker tracker = new MediaTracker(this);
        URL fontUrl = null;
        try
        {
            fontUrl = new URL(path);
        }
        catch (MalformedURLException e)
        {
            e.printStackTrace();
        }
        // 此方法为异步
        Image fotImage = Toolkit.getDefaultToolkit().getImage(fontUrl);

        tracker.addImage(fotImage, 1);

        try
        {
            tracker.waitForAll();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        return fotImage;

    }

}

楼主在本地添加参数-Djava.awt.headless=false调试并且运行成功,但是一上linux服务,fuck又不行
最后报错
Can’t connect to X11 window server using ‘:0.0′ as the value of the DISPLAY variable

楼主去研究了下,最后得出结论,使用这个api必须系统要支持图形化操作界面

当到这里的时候,楼主想死的心都有了

最后改进

不能使用同步的方法了,经过我观察,总是水印图加载部分,或者加载失败。最后试了试水印图使用ImageIo.read方法来读取,代码如下

这个toBufferedImage方法在上面

 		String blackPath = "";
        String fontPath = "";

        // 水印图
        URL frontUrl = new URL(fontPath);
        // 地图
        URL blackUrl = new URL(blackPath);
        // 读取水印图
        Image frontImage = ImageIO.read(frontUrl);
        // 读取背景图
        Image blackImage = Toolkit.getDefaultToolkit().getImage(blackUrl);

        BufferedImage image = toBufferedImage(blackImage);
        // 拉伸下,
        Thumbnails.Builder<BufferedImage> of = Thumbnails.of(image).size(750, 750);
        image = of.asBufferedImage();
        Graphics2D g2d = image.createGraphics();
        // 在地图上绘制水印
        g2d.drawImage(frontImage, 0, 0, 750, 750, null);
        g2d.dispose();

最后附图
在这里插入图片描述

最后还真的让楼主成功了,这些问题记录下,顺便述说下楼主的辛酸。如果哪位大佬有更好的方法,或者更好的工具包出来,欢迎指点。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值