根据明暗度分别加不同的水印

本文介绍了一种利用Java编程语言实现图像水印插入的方法,包括如何获取指定矩形区域的像素矩阵,以及如何根据水印图片的亮度和源图片的灰度边界调整水印的显示效果。
 
package image;import java.awt.alphacomposite;import java.awt.color;import java.awt.font;import java.awt.graphics;import java.awt.graphics2d;import java.awt.image;import java.awt.image.bufferedimage;import java.awt.image.colormodel;import java.awt.image.pixelgrabber;import java.io.file;import java.io.fileoutputstream;import javax.imageio.imageio;import com.sun.image.codec.jpeg.jpegcodec;import com.sun.image.codec.jpeg.jpegimageencoder;public class watermark {    /**     * 获取指定矩形中的像素的矩阵     *      * @param imagesrc     * @param startx     * @param starty     * @param w     * @param h     * @return     */    private int[] getpixarray(image imagesrc, int startx, int starty,            int w, int h) {        int[] pix = new int[(w - startx) * (h - starty)];                /*下面是别人程序中的一段,我实在不明白为何要加这一段,因为我去掉也没有问题,加上还会报错*/        pixelgrabber pg = null;        try {            pg = new pixelgrabber(imagesrc, startx, starty, w-startx, h-starty, pix, 0, w);            if (pg.grabpixels() != true) {                try {                    throw new java.awt.awtexception("pg error" + pg.status());                } catch (exception eq) {                    eq.printstacktrace();                }            }        } catch (exception ex) {            ex.printstacktrace();        }        return pix;    }    /**     * 将1张图片和另1张图片的指定区域重合。可用于制作水印。图片的左上角坐标为0,0     *      * @param lightnesswaterimg     *            颜色比较亮的水印图片,适合底色比较暗的情况     * @param darknesswaterimg     *            颜色比较暗的水印图片,适合底色比较亮的情况,如果不想区分,则输入null,平均灰度边界同时失效。     * @param targetimg     *            源图片     * @param startx     * @param starty     * @param x     * @param y     * @param alpha     *            透明度,0f为全透明,1f为完全不透明,0.5f为半透明     * @param averagegray     *            平均灰度边界(0-255),大于此值,则打暗的水印图片,小于此值则打亮的水印图片。     *            默认值128。超过范围,按默认值进行。     */    private final void pressimage(string lightnesswaterimg,            string darknesswaterimg, string targetimg, int startx, int starty,            int x, int y, float alpha, float averagegray) {        try {            // 先判断亮水印和源文件的值是否为null,否则抛出异常            if (lightnesswaterimg == null || lightnesswaterimg == ""                    || targetimg == null || targetimg == "") {                throw new exception("亮水印或者源图片的地址不能为空");            }             // 再判断平均灰度边界是否越界            if (averagegray>255||averagegray<0) {                averagegray = 128;            }                        // 装载源图片            file _file = new file(targetimg);            // 图片装入内存            bufferedimage src = imageio.read(_file);            // 获取图片的尺寸            int width = src.getwidth(null);            int height = src.getheight(null);            // 根据源图片尺寸,设置预装载的一个图片,默认是rgb格式的            bufferedimage image = new bufferedimage(width, height,                    bufferedimage.type_int_rgb);            graphics2d graphics = image.creategraphics();            // 绘制内存中的源图片至指定的矩形内            graphics.drawimage(src, 0, 0, width, height, null);            // 在已经绘制的图片中加入透明度通道            graphics.setcomposite(alphacomposite.getinstance(                    alphacomposite.src_atop, alpha));                        // 获取源图片中和设定的同样大小的区域内的像素集合            int[] pixels = getpixarray(src, startx, starty, x, y);            //查询此集合的平均灰度            float average = getaveragegrap(x-startx,y-starty,pixels);            // 如果平均灰度大于130,则说明此区域比较亮,否则则比较暗            system.out.println(average);                        //装载水印图片所需参数            file water;            bufferedimage bufferwater;                        // 根据设定的平均灰度边界来装载不同的水印            if (darknesswaterimg == null||average>=averagegray) {                // 装载亮水印文件                water = new file(darknesswaterimg);            }else{                // 装载暗水印文件                water = new file(lightnesswaterimg);            }            // 装入内存            bufferwater = imageio.read(water);                                    graphics.drawimage(bufferwater, startx, starty, x, y,                    null);            // 水印文件结束            graphics.dispose();            fileoutputstream out = new fileoutputstream(targetimg);            jpegimageencoder encoder = jpegcodec.createjpegencoder(out);            // 绘制新的文件            encoder.encode(image);            out.close();                    } catch (exception e) {            e.printstacktrace();        }    }            /**     * 查询某个区域的平均灰度     * @param width     * @param height     * @param pixels     * @return     */    private float getaveragegrap(int width,int height,int[] pixels){        /* 下面是开始算这个区域的亮度了,灰度等同于亮度 */        colormodel colormodel = colormodel.getrgbdefault();        int i = 0;        int j = 0;        int k = 0;        int r = 0;        int g = 0;        int b = 0;        int gray = 0;        float average = 0;// 平均灰度        for (i = 0; i < height; i++) {            for (j = 0; j < width; j++) {                // 定位像素点                k = i * width + j;                r = colormodel.getred(pixels[k]);                g = colormodel.getgreen(pixels[k]);                b = colormodel.getblue(pixels[k]);                // 计算灰度值                gray = (r * 38 + g * 75 + b * 15) >> 7;                average = average + gray;            }        }        // 计算平均灰度        average = average / ((i - 1) * (j - 1));        return average;    }    public static void main(string[] args) {        watermark watermark = new watermark();        watermark.pressimage("f:\\a2.png", "a1.png",                "2.jpg", 520, 500, 900, 800, 0.5f, 50);        system.out.print("添加成功");    }}
 
分析下面语句 private static void addWatermarkToPage(PDDocument doc, PDPage page, PDType0Font font) { try (PDPageContentStream stream = new PDPageContentStream( doc, page, PDPageContentStream.AppendMode.APPEND, true, true)) { // 获取页面尺寸 PDRectangle pageSize = page.getMediaBox(); float pageWidth = pageSize.getWidth(); float pageHeight = pageSize.getHeight(); // 设置水印样式 stream.setFont(font, FONT_SIZE); stream.setNonStrokingColor(Color.LIGHT_GRAY); // 计算文本尺寸(核心优化) float textWidth = font.getStringWidth(WATERMARK_TEXT) * FONT_SIZE / 1000; float textHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE / 1000; // 计算旋转后实际占位尺寸 double rads = Math.toRadians(ROTATION_ANGLE); float rotatedWidth = (float) (Math.abs(textWidth * Math.cos(rads)) + Math.abs(textHeight * Math.sin(rads))); float rotatedHeight = (float) (Math.abs(textWidth * Math.sin(rads)) + Math.abs(textHeight * Math.cos(rads))); // 计算行列数(确保覆盖边界) int cols = (int) Math.ceil((pageWidth + rotatedWidth * 2) / rotatedWidth); int rows = (int) Math.ceil((pageHeight + rotatedHeight * 2) / rotatedHeight); // 添偏移量覆盖边缘区域(关键优化点) float offsetX = -rotatedWidth; float offsetY = -rotatedHeight; // 平铺水印(全覆盖算法) for (int row = 0; row <= rows; row++) { float y = offsetY + row * rotatedHeight; // 交错布局(奇数行偏移) float rowOffset = (row % 2 == 0) ? 0 : rotatedWidth * 0.5f; for (int col = 0; col <= cols; col++) { float x = offsetX + col * rotatedWidth + rowOffset; drawWatermark(stream, WATERMARK_TEXT, font, x + rotatedWidth/2, y + rotatedHeight/2); } } } catch (Exception e) { System.err.println("水印失败: " + e.getMessage()); } } private static void drawWatermark(PDPageContentStream stream, String text, PDType0Font font, float centerX, float centerY) throws IOException { stream.saveGraphicsState(); stream.beginText(); // 设置旋转中心(优化定位) stream.transform(Matrix.getRotateInstance( Math.toRadians(ROTATION_ANGLE), centerX, centerY)); // 计算文本偏移量(居中显示) float textOffsetX = -font.getStringWidth(text) * FONT_SIZE / 2000; float textOffsetY = -font.getFontDescriptor().getFontBoundingBox().getHeight() * FONT_SIZE / 2000; stream.newLineAtOffset(centerX + textOffsetX, centerY + textOffsetY); stream.showText(text); stream.endText(); stream.restoreGraphicsState(); }
最新发布
09-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值