JAVA給照片添加平鋪水印並解決javax.imageio.IIOException: Unsupported Image Type異常

目錄

 

聲明:

操作:

1、第一步引入pom文件

2、在resources目錄下添加ISOcoated_v2_300_eci.icc文件

3、添加工具文件生成水印圖片類

4、測試結果


聲明:

此文章是給照片生成平鋪水印的照片文件,並解決javax.imageio.IIOException: Unsupported Image Type異常,

javax.imageio.IIOException: Unsupported Image Type異常的產生原因是因爲圖片的顏色模式具體錯誤描述請看另一篇文章

點擊跳轉:javax.imageio.IIOException: Unsupported Image Type異常詳解

此文章僅發佈成功生產平鋪水印無異常的照片文件

操作:

1、第一步引入pom文件

本身生產水印圖片的方法不用引入pom文件,僅僅使用java.awt包即可,但是這裏是解決異常問題,所以添加了其他pom文件解決問題

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-imaging</artifactId>
            <version>1.0-alpha1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.sanselan</groupId>
            <artifactId>sanselan</artifactId>
            <version>0.97-incubator</version>
        </dependency>

2、在resources目錄下添加ISOcoated_v2_300_eci.icc文件

ISOcoated_v2_300_eci.icc此文件爲解決顏色轉碼失去準確性的文件,也是爲了解決異常問題

文件下載地址

 

3、添加工具文件生成水印圖片類

import javax.imageio.ImageIO;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author aliceqixin
 * @Title ImageWatermarkUtil
 * @Description
 * @date 2019年9月18日 下午4:47:38
 */
public class ImageWatermarkUtil {
    // 水印透明度
    private float alpha = 0.2f;


    /**
     * 獲取文本長度。漢字爲1:1,英文和數字爲2:1
     */
    private int getTextLength(String text) {
        int length = text.length();
        for (int i = 0; i < text.length(); i++) {
            String sparam = String.valueOf(text.charAt(i));
            if (sparam.getBytes().length > 1) {
                length++;
            }
        }
        length = length % 2 == 0 ? length / 2 : length / 2 + 1;
        return length;
    }


    /**
     * 給圖片添加水印文字、可設置水印文字的旋轉角度
     *
     * @param logoText   水印內容
     * @param srcImg     源圖片
     * @param targerPath 生成水印文件路徑
     * @param degree     傾斜度
     */
    public void imageByText(String logoText, Image srcImg, String targerPath, Integer degree) {

        InputStream is = null;
        OutputStream os = null;
        try {
            // 源圖片
            int heightParam = srcImg.getHeight(null);// 原圖高度
            int widthParam = srcImg.getWidth(null);// 原圖寬度
            // 水印文字大小
            int fontSize = 80;
            // 水印文字字體
            Font font = new Font("微軟雅黑", Font.BOLD, heightParam/50);
            // 水印文字顏色
            Color color = Color.gray;
            // 水印之間的間隔
            int xmove = widthParam/6;
            // 水印之間的間隔
            int ymove = heightParam/6;


            BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null), srcImg.getHeight(null),
                    BufferedImage.TYPE_INT_RGB);
            // 得到畫筆對象
            Graphics2D graphics = buffImg.createGraphics();
            // 設置對線段的鋸齒狀邊緣處理
            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            graphics.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null),
                    Image.SCALE_SMOOTH),
                    0, 0, null);
            // 設置水印旋轉
            if (null != degree) {
                graphics.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2,
                        (double) buffImg.getHeight() / 2);
            }
            // 設置水印文字顏色
            graphics.setColor(color);
            // 設置水印文字Font
            graphics.setFont(font);
            // 設置水印文字透明度
            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            int xparam = -widthParam / 2;
            int yparam = -heightParam / 2;
            int markWidth = fontSize * getTextLength(logoText);// 字體長度
            int markHeight = fontSize;// 字體高度

            // 循環添加水印
            while (xparam < widthParam * 100) {
                yparam = -heightParam / 2;
                while (yparam < heightParam * 100) {
                    graphics.drawString(logoText, xparam, yparam);

                    yparam += markHeight + ymove;
                }
                xparam += markWidth + xmove;
            }
            // 釋放資源
            graphics.dispose();
            // 生成圖片
            os = new FileOutputStream(targerPath);
            ImageIO.write(buffImg, "JPG", os);
            System.out.println("添加水印文字成功!");
        } 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();
            }
        }
    }


}
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

public class JpegReader {

    public static final int COLOR_TYPE_RGB = 1;
    public static final int COLOR_TYPE_CMYK = 2;
    public static final int COLOR_TYPE_YCCK = 3;

    private int colorType = COLOR_TYPE_RGB;
    private boolean hasAdobeMarker = false;

    public BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorType = COLOR_TYPE_RGB;
        hasAdobeMarker = false;

        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK)
                    convertYcckToCmyk(raster);
                if (hasAdobeMarker)
                    convertInvertedColors(raster);
                image = convertCmykToRgb(raster, profile);
            }

            return image;
        }

        return null;
    }

    public void checkAdobeMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
            {
                hasAdobeMarker = true;
                int transform = app14Segment.bytes[11] & 0xff;
                if (transform == 2)
                    colorType = COLOR_TYPE_YCCK;
            }
        }
    }

    public static void convertYcckToCmyk(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);

            for (int x = 0; x < stride; x += 4) {
                int y = pixelRow[x];
                int cb = pixelRow[x + 1];
                int cr = pixelRow[x + 2];

                int c = (int) (y + 1.402 * cr - 178.956);
                int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int) (y + 1.772 * cb - 226.316);

                if (c < 0) c = 0; else if (c > 255) c = 255;
                if (m < 0) m = 0; else if (m > 255) m = 255;
                if (y < 0) y = 0; else if (y > 255) y = 255;

                pixelRow[x] = 255 - c;
                pixelRow[x + 1] = 255 - m;
                pixelRow[x + 2] = 255 - y;
            }

            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static void convertInvertedColors(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);
            for (int x = 0; x < stride; x++)
                pixelRow[x] = 255 - pixelRow[x];
            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
        if (cmykProfile == null)
            cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));

        if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
            byte[] profileData = cmykProfile.getData();

            if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
                intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first

                cmykProfile = ICC_Profile.getInstance(profileData);
            }
        }

        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
        BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykRaster, rgbRaster);
        return rgbImage;
    }

    static void intToBigEndian(int value, byte[] array, int index) {
        array[index]   = (byte) (value >> 24);
        array[index+1] = (byte) (value >> 16);
        array[index+2] = (byte) (value >>  8);
        array[index+3] = (byte) (value);
    }

}



 

4、測試結果

如果想讓水印旋轉可以修改ImageByText (logoText, srcImg, targerPath, -10);參數 -10代表旋轉角度,可自行調試

結束!感謝觀看~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章