2 xiaoliuing xiaoliuing 于 2015.06.09 15:23 提问

怎么用java图片加文字水印ne

要一个完整的例子,传入的参数最好是
源文件 byte[] 文字内容

返回的是加水印之后的 byte[]

最好有注释,谢谢了

Exception in thread "main" sun.misc.ServiceConfigurationError: javax.imageio.spi.ImageReaderSpi: Provider it.geosolutions.imageio.stream.input.spi.FileImageInputStreamExtImplSpi not a subtype at sun.misc.Service.fail(Service.java:129) at sun.misc.Service.access$000(Service.java:111) at sun.misc.Service$LazyIterator.next(Service.java:278) at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(IIORegistry.java:190) at javax.imageio.spi.IIORegistry.(IIORegistry.java:121) at javax.imageio.spi.IIORegistry.getDefaultInstance(IIORegistry.java:142) at javax.imageio.ImageIO.(ImageIO.java:48) at com.xiaoliu.mobile.WaterMarker.changeImg2Byte(WaterMarker.java:64) at com.xiaoliu.mobile.WaterMarker.main(WaterMarker.java:36)


4个回答

tongyi55555
tongyi55555   2015.06.09 16:59
已采纳

以下是根据byte[]对象来进行文字水印的添加,主要涉及的就是图像对象如何与byte[]数组转换的问题,还是使用图像画笔进行的水印添加,水印文字添加在图像的正中央。
可根据需要修改水印字体样式和透明度。代码如下:

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

/**
 * 文字水印
 * 参考 http://sjsky.iteye.com/blog/1154390
 * 参考
 */
public class ImageMarkLogoByText {

    /**
     * @param args
     */
    public static void main(String[] args) {
        String srcImgPath = "d:/01.jpg";
        String logoText = "[ 测试文字水印 http://ask.csdn.net]";
        String targerPath = "d:/img_mark_text.jpg";

        // 现在已知的是图片路径,所以需要自己转换成byte数组,如果你有byte数组直接使用下面的方法
        byte[] srcImgByte = changeImg2Byte(srcImgPath);

        // 给图片添加水印,需要传入文字和图片的byte数组,返回结果是加了水印的图片byte[]对象
        byte[] resultByte = ImageMarkLogoByText
                .markByText(logoText, srcImgByte);

        // 为了便于查看,下面对结果进行了输出
        BufferedImage resultImage = changeByte2Img(resultByte);
        try {
            ImageIO.write(resultImage, "JPG", new FileOutputStream(targerPath));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 根据传入的图像文件路径读取图像,并存入到byte数组中。
     * 
     * @param srcImgPath
     * @return
     */
    private static byte[] changeImg2Byte(String srcImgPath) {
        // TODO Auto-generated method stub
        try {
            BufferedImage image = ImageIO.read(new File(srcImgPath));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", out);
            byte[] b = out.toByteArray();
            return b;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 给图片添加文字水印
     * 
     * @param logoText
     * @param srcByteImg
     */
    public static byte[] markByText(String logoText, byte[] srcByteImg) {
        InputStream is = null;
        ByteArrayOutputStream os = null;
        try {

            // 获取image对象,没有他做不了绘制
            BufferedImage buffImg = changeByte2Img(srcByteImg);

            // 得到画笔对象
            Graphics2D g = buffImg.createGraphics();

            // 设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            int width = buffImg.getWidth(null);
            int height = buffImg.getHeight(null);
            g.drawImage(buffImg.getScaledInstance(width, height,
                    Image.SCALE_SMOOTH), 0, 0, null);

            // 设置颜色
            g.setColor(Color.red);

            // 设置 Font
            g.setFont(new Font("宋体", Font.BOLD, 30));
            FontMetrics fontMetrics = g.getFontMetrics();
            int logoWidth = fontMetrics.stringWidth(logoText);
            // 设置水印的透明度
            float alpha = 0.5f;
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                    alpha));

            // 第一参数->设置的内容,后面两个参数->文字左上角在图片上的坐标位置(x,y),简单点设置文字在中心,竖直方向有些偏差 .
            g.drawString(logoText, (width - logoWidth) / 2, height / 2
                    +fontMetrics.getAscent()/2 - fontMetrics.getDescent()/2);

            g.dispose();

            // 生成图片
            os = new ByteArrayOutputStream();
            ImageIO.write(buffImg, "JPG", os);
            System.out.println("图片完成添加文字印章。。。。。。");
            // 返回图片的byte数组
            return os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != is)
                    is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if (null != os)
                    os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根据传入的图像byte数组转换成图像
     * 
     * @param srcByteImg
     * @return
     */
    private static BufferedImage changeByte2Img(byte[] srcByteImg) {
        // TODO Auto-generated method stub
        ByteArrayInputStream in = new ByteArrayInputStream(srcByteImg);
        try {
            BufferedImage image = ImageIO.read(in);
            return image;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

原始图像:

图片说明

结果图像:

图片说明

xiaoliuing
xiaoliuing 回复那一抹代码: 我不是做GIS的,我直接把你的代码复制来,然后图片换成我本地的图片,run as application,就出现这个错误了
2 年多之前 回复
xiaoliuing
xiaoliuing 回复那一抹代码: 完整的错误信息我放到问题后边了,或者可不可以加下大神QQ,我的是523649919
2 年多之前 回复
xiaoliuing
xiaoliuing 我不是做GIS的,我直接把你的代码复制来,然后图片换成我本地的图片,run as application,就出现这个错误了
2 年多之前 回复
tongyi55555
tongyi55555 回复奔跑的小羊儿: 你能详细介绍你是怎么使用的么?完整的错误信息能提供么?你也是做GIS的?
2 年多之前 回复
tongyi55555
tongyi55555 回复奔跑的小羊儿: 你能详细介绍你是怎么使用的么?完整的错误信息能提供么?你也是做GIS的?
2 年多之前 回复
xiaoliuing
xiaoliuing 我的jdk是1.6 tomcat是5.0
2 年多之前 回复
xiaoliuing
xiaoliuing 但是在我运行的时候 有个异常,我特别头疼,能帮我看下吗 就是这个:Exception in thread "main" sun.misc.ServiceConfigurationError: javax.imageio.spi.ImageReaderSpi: Provider it.geosolutions.imageio.stream.input.spi.FileImageInputStreamExtImplSpi not a subtype
2 年多之前 回复
xiaoliuing
xiaoliuing 谢谢 非常感谢大神的代码,就是我想要的东西。
2 年多之前 回复
devmiao
devmiao   Ds   Rxr 2015.06.09 15:26
xiaoliuing
xiaoliuing 这个是可以的,它是 提供图片路径 然后加水印之后直接覆盖原图,我是提供二进制数据流然后返回加水印之后的byte[], 我在网上搜了,有用这的有用那得,我头大了,所以想要个有注释的
2 年多之前 回复
datou431
datou431   Rxr 2015.06.09 15:36

用过滤器,等我上线给你,不要结问题哦
package com.jc.ts.services;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
*添加图片水印的服务类

  • / public class WaterMark { /*
    • @param sizeContext添加水印文字
    • @param request 请求流对象
    • @param request 响应流对象
    • / @SuppressWarnings("deprecation") public static void createMarkSize(String sizeContext,HttpServletRequest request,HttpServletResponse response) { try { String path=request.getRealPath(request.getServletPath()); FileInputStream in=new FileInputStream(path); Image src=ImageIO.read(in); int w=src.getWidth(null); int h=src.getHeight(null); BufferedImage img=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);//构建画板 Graphics g=img.getGraphics();//得到画笔 g.drawImage(src,0,0,w,h,null);//把源图片写入画板 g.setColor(Color.red); g.drawString(sizeContext,10,5); // 添加文字 g.dispose();//生成图片 JPEGImageEncoder e=JPEGCodec.createJPEGEncoder(response.getOutputStream()); e.encode(img); response.getOutputStream().close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ImageFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /*
    • @param localPath 添加水印LOGO路径
    • @param request 请求流对象
    • @param request 响应流对象 **/ @SuppressWarnings("deprecation") public static void createMarkLogo(String localPath,HttpServletRequest request,HttpServletResponse response) { try { FileInputStream file=new FileInputStream(localPath); Image fimg=ImageIO.read(file); int fw=fimg.getWidth(null); int fh=fimg.getHeight(null); String path=request.getRealPath(request.getServletPath()); FileInputStream in=new FileInputStream(path); Image src=ImageIO.read(in); int w=src.getWidth(null); int h=src.getHeight(null); BufferedImage img=new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);//构建画板 Graphics g=img.getGraphics();//得到画笔 g.drawImage(src,0,0,w,h,null);//把原图片写入画板 g.drawImage(fimg,w-20,h-15,fw,fh,null);//把水印图片写入画板 g.dispose();//生成图片 JPEGImageEncoder e=JPEGCodec.createJPEGEncoder(response.getOutputStream()); e.encode(img); response.getOutputStream().close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ImageFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

}

  /** 
* @param localPath 添加水印图片路径
* @param request 请求流对象
* @param request 响应流对象
              * @param width   水印图片的宽度
              * @param height  水印图片的长度
**/
@SuppressWarnings("deprecation")

public static void createMarkLogo(String localPath,HttpServletRequest request,HttpServletResponse response,int width,int height) {
try {
FileInputStream file=new FileInputStream(localPath);
Image fimg=ImageIO.read(file);
int fw=fimg.getWidth(null);
int fh=fimg.getHeight(null);
String path=request.getRealPath(request.getServletPath());
FileInputStream in=new FileInputStream(path);
Image src=ImageIO.read(in);
int w=src.getWidth(null);//w为你过滤图片的宽度
int h=src.getHeight(null);//h为你过滤图片的长度
BufferedImage img=new BufferedImage(w+width,h+height,BufferedImage.TYPE_INT_RGB);//构建画板(画板的宽度为两个图片之和)
Graphics g=img.getGraphics();//得到画笔
g.drawImage(src,0,0,w,h,null);//把原图片写入画板
g.drawImage(fimg,width,height,fw,fh,null);//把水印图片写入画板
g.dispose();//生成图片
JPEGImageEncoder e=JPEGCodec.createJPEGEncoder(response.getOutputStream());
e.encode(img);
response.getOutputStream().close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ImageFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

注意第三个方法的注释地方g.drawImage(fimg,width,height,fw,fh,null);根据参数你在调调(放原图下面的)

过滤器调用
package com.jc.ts.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jc.ts.services.WaterMark;

public class WaterFilter implements Filter {

public void destroy() {
// TODO Auto-generated method stub

}
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)arg0;
HttpServletResponse response=(HttpServletResponse)arg1;
//WaterMark.createMarkSize("南京ts", request, response);
//WaterMark.createMarkLogo("D:\workspace\mybook\WebRoot\images\logo\book.jpg", request, response);
WaterMark.createMarkLogo("D:\workspace\mybook\WebRoot\images\logo\book.jpg", request, response,20,30);
//注意路径为绝对路径且三个效果不能同时执行

}

public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub

}

}

web.xml配置(写在servlet上面)


This is the description of my J2EE component
This is the display name of my J2EE component
WaterFilter
com.jc.ts.filter.WaterFilter

希望你能满意。。。。。。

xiaoliuing
xiaoliuing 亲 你的这个回复 源自百度知道 我在提问之前肯定已经在网上搜过了,就是不明白所以要个有注释的,麻烦就不要复制别人的了,谢谢亲
2 年多之前 回复
sxjiangdongqin
sxjiangdongqin   2015.06.10 08:13

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.swing.*;
import com.sun.image.codec.jpeg.*;
public class WaterSet {
/** //*
* 给图片添加水印
*
* @param filePath
* 需要添加水印的图片的路径
* @param markContent
* 水印的文字
* @param markContentColor
* 水印文字的颜色
* @param qualNum
* 图片质量
* @return
*/
public boolean createMark(String filePath, String markContent,
Color markContentColor, float qualNum) {
ImageIcon imgIcon = new ImageIcon(filePath);
Image theImg = imgIcon.getImage();
int width = theImg.getWidth(null);
int height = theImg.getHeight(null);
BufferedImage bimage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimage.createGraphics();
g.setColor(markContentColor);
g.setBackground(Color.white);
g.drawImage(theImg, 0, 0, null);
g.drawString(markContent, width / 5, height / 5); // 添加水印的文字和设置水印文字出现的内容
g.dispose();
try {
FileOutputStream out = new FileOutputStream(filePath);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
param.setQuality(qualNum, true);
encoder.encode(bimage, param);
out.close();
} catch (Exception e) {
return false;
}
return true;
}
}

Csdn user default icon
上传中...
上传图片
插入图片