目录
声明:
操作:
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异常详解
此文章仅发布成功生产平铺水印无异常的照片文件
本身生产水印图片的方法不用引入pom文件,仅仅使用java.awt包即可,但是这里是解决异常问题,所以添加了其他pom文件解决问题
org.apache.commons
commons-imaging
1.0-alpha1
org.apache.sanselan
sanselan
0.97-incubator
ISOcoated_v2_300_eci.icc此文件为解决颜色转码失去准确性的文件,也是为了解决异常问题
文件下载地址
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 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);
}
}
如果想让水印旋转可以修改ImageByText (logoText, srcImg, targerPath, -10);参数 -10代表旋转角度,可自行调试
结束!感谢观看~