文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

手把手教你如何给图像加水印

2024-12-02 17:23

关注

一、介绍

在实际的系统开发中,某些业务场景下,我们经常需要给原始图片添加水印,以防止图片信息在互联网上随意传播!

也有的基于当下的业务需求,需要给相机照片加水印、地理位置、时间等信息,以方便记录自己的生活!

例如下图!

有的人可能很容易想到,通过 PS 技术就可以很轻松的完成!

的确,对于单个图像而言很容易,但是对于成千上万的图像,采用人工处理,显然不可取!

问题来了,面对大批量的图像加水印需求,我们应当如何处理呢?

试想一下,如果我们采用人工方式来给图像添加水印,大概的步骤离不开以下几步:

如果采用程序来实现,思路也是一样的,废话也不多说了,代码直接撸上!

二、程序实践

下面我们以java程序为例,给以下图添加一段复印无效的文字水印,并居中!

程序实践如下:

  1. import org.apache.commons.lang3.StringUtils; 
  2. import javax.imageio.ImageIO; 
  3. import java.awt.*; 
  4. import java.awt.image.BufferedImage; 
  5. import java.io.File; 
  6.  
  7.  
  8. public class ImageWaterMarkUtil { 
  9.  
  10.  
  11.  
  12.      
  13.     public static void markImage(String srcImgPath, 
  14.                                  String targetImgPath, 
  15.                                  String text, 
  16.                                  Color color, 
  17.                                  Font font, 
  18.                                  float alpha, 
  19.                                  int positionWidth, 
  20.                                  int positionHeight, 
  21.                                  Integer degree, 
  22.                                  String location) { 
  23.         try { 
  24.             // 1、读取源图片 
  25.             Image srcImg = ImageIO.read(new File(srcImgPath)); 
  26.             int srcImgWidth = srcImg.getWidth(null); 
  27.             int srcImgHeight = srcImg.getHeight(null); 
  28.             BufferedImage buffImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); 
  29.  
  30.             // 2、得到画笔对象 
  31.             Graphics2D g = buffImg.createGraphics(); 
  32.             // 3、设置对线段的锯齿状边缘处理 
  33.             g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
  34.             g.drawImage(srcImg.getScaledInstance(srcImgWidth, srcImgHeight, Image.SCALE_SMOOTH), 0, 0, null); 
  35.             // 4、设置水印旋转 
  36.             if (null != degree) { 
  37.                 g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2); 
  38.             } 
  39.             // 5、设置水印文字颜色 
  40.             g.setColor(color); 
  41.             // 6、设置水印文字Font 
  42.             g.setFont(font); 
  43.             // 7、设置水印文字透明度 
  44.             g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); 
  45.             // 8、水印图片的位置 
  46.             int x = 0, y = 0; 
  47.             if (StringUtils.equals(location, "left-top")) { 
  48.                 x = 30; 
  49.                 y = font.getSize(); 
  50.             } else if (StringUtils.equals(location, "right-top")) { 
  51.                 x = srcImgWidth - getWatermarkLength(text, g) - 30; 
  52.                 y = font.getSize(); 
  53.             } else if (StringUtils.equals(location, "left-bottom")) { 
  54.                 x += 30; 
  55.                 y = buffImg.getHeight() - font.getSize(); 
  56.             } else if (StringUtils.equals(location, "right-bottom")) { 
  57.                 x = srcImgWidth - getWatermarkLength(text, g) - 30; 
  58.                 y = srcImgHeight - font.getSize(); 
  59.             } else if (StringUtils.equals(location, "center")) { 
  60.                 x = (srcImgWidth - getWatermarkLength(text, g)) / 2; 
  61.                 y = srcImgHeight / 2; 
  62.             } else { 
  63.                 //自定义位置 
  64.                 x = positionWidth; 
  65.                 y = positionHeight; 
  66.             } 
  67.             // 9、第一参数->设置的内容,后面两个参数->文字在图片上的坐标位置(x,y) 
  68.             g.drawString(text, x, y); 
  69.             // 10、释放资源 
  70.             g.dispose(); 
  71.             // 11、生成图片 
  72.             ImageIO.write(buffImg, "png", new File(targetImgPath)); 
  73.             System.out.println("图片完成添加水印文字"); 
  74.         } catch (Exception e) { 
  75.             e.printStackTrace(); 
  76.         } 
  77.     } 
  78.  
  79.      
  80.     private static int getWatermarkLength(String text, Graphics2D g) { 
  81.         return g.getFontMetrics(g.getFont()).charsWidth(text.toCharArray(), 0, text.length()); 
  82.     } 
  83.  
  84.     public static void main(String[] args) { 
  85.         String srcImgPath = "/Users/pzblog/Desktop/Jietu.jpg"; //原始文件地址 
  86.         String targetImgPath = "/Users/pzblog/Desktop/Jietu-copy.jpg"; //目标文件地址 
  87.         String text = "复 印 无 效"; //水印文字内容 
  88.         Color color = Color.red; //水印文字颜色 
  89.         Font font = new Font("宋体", Font.BOLD, 60); //水印文字字体 
  90.         float alpha = 0.4f; //水印透明度 
  91.         int positionWidth = 320; //水印横向位置坐标 
  92.         int positionHeight = 450; //水印纵向位置坐标 
  93.         Integer degree = -30; //水印旋转角度 
  94.         String location = "center"; //水印的位置 
  95.         //给图片添加文字水印 
  96.         markImage(srcImgPath, targetImgPath, text, color, font, alpha, positionWidth, positionHeight, degree, location); 
  97.     } 

运行结果如下:

水印添加成功!

2.1、给图像添加多处文字

有的需求会要求给图像添加多处文字水印,例如下图!

处理过程也很简单!

  1. import javax.imageio.ImageIO; 
  2. import java.awt.*; 
  3. import java.awt.image.BufferedImage; 
  4. import java.io.File; 
  5.  
  6.  
  7. public class ImageFullWaterMarkUtil { 
  8.  
  9.  
  10.  
  11.      
  12.     public static void fullMarkImage(String srcImgPath, 
  13.                                  String targetImgPath, 
  14.                                  String text, 
  15.                                  Color color, 
  16.                                  Font font, 
  17.                                  float alpha, 
  18.                                  int startWidth, 
  19.                                  Integer degree, 
  20.                                  Integer interval) { 
  21.         try { 
  22.             // 1、读取源图片 
  23.             Image srcImg = ImageIO.read(new File(srcImgPath)); 
  24.             int srcImgWidth = srcImg.getWidth(null); 
  25.             int srcImgHeight = srcImg.getHeight(null); 
  26.             BufferedImage buffImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); 
  27.  
  28.             // 2、得到画笔对象 
  29.             Graphics2D g = buffImg.createGraphics(); 
  30.             // 3、设置对线段的锯齿状边缘处理 
  31.             g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
  32.             g.drawImage(srcImg.getScaledInstance(srcImgWidth, srcImgHeight, Image.SCALE_SMOOTH), 0, 0, null); 
  33.             // 4、设置水印旋转 
  34.             if (null != degree) { 
  35.                 g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2); 
  36.             } 
  37.             // 5、设置水印文字颜色 
  38.             g.setColor(color); 
  39.             // 6、设置水印文字Font 
  40.             g.setFont(font); 
  41.             // 7、设置水印文字透明度 
  42.             g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); 
  43.             // 8、水印图片的位置 
  44.             int x = startWidth; 
  45.             int y = font.getSize(); 
  46.             int space = srcImgHeight / interval; 
  47.             for (int i = 0; i < space; i++) { 
  48.                 //如果最后一个坐标的y轴比height高,直接退出 
  49.                 if (((y + font.getSize()) > srcImgHeight) || ((x + getWatermarkLength(text,g))  > srcImgWidth)) { 
  50.                     break; 
  51.                 } 
  52.                 //9、进行绘制 
  53.                 g.drawString(text, x, y); 
  54.                 x += getWatermarkLength(text,g); 
  55.                 y += font.getSize() + interval; 
  56.             } 
  57.             // 10、释放资源 
  58.             g.dispose(); 
  59.             // 11、生成图片 
  60.             ImageIO.write(buffImg, "png", new File(targetImgPath)); 
  61.             System.out.println("图片完成添加水印文字"); 
  62.         } catch (Exception e) { 
  63.             e.printStackTrace(); 
  64.         } 
  65.     } 
  66.  
  67.      
  68.     private static int getWatermarkLength(String text, Graphics2D g) { 
  69.         return g.getFontMetrics(g.getFont()).charsWidth(text.toCharArray(), 0, text.length()); 
  70.     } 
  71.  
  72.     public static void main(String[] args) { 
  73.         String srcImgPath = "/Users/pzblog/Desktop/Jietu.jpg"; //原始文件地址 
  74.         String targetImgPath = "/Users/pzblog/Desktop/Jietu-copy-full.jpg"; //目标文件地址 
  75.         String text = "复 印 无 效"; //水印文字内容 
  76.         Color color = Color.red; //水印文字颜色 
  77.         Font font = new Font("宋体", Font.BOLD, 30); //水印文字字体 
  78.         float alpha = 0.4f; //水印透明度 
  79.         int startWidth = 30; //水印横向位置坐标 
  80.         Integer degree = -0; //水印旋转角度 
  81.         Integer interval = 100; //水印的位置 
  82.         //给图片添加文字水印 
  83.         fullMarkImage(srcImgPath, targetImgPath, text, color, font, alpha, startWidth, degree, interval); 
  84.     } 

2.2、给图像添加图片水印

某些情况下,我们还需要给图像添加图片水印,例如下图效果!

处理过程也很简单!

  1. import org.apache.commons.lang3.StringUtils; 
  2.  
  3. import javax.imageio.ImageIO; 
  4. import javax.swing.*; 
  5. import java.awt.*; 
  6. import java.awt.image.BufferedImage; 
  7. import java.io.File; 
  8.  
  9.  
  10. public class ImageIconWaterMarkUtil { 
  11.  
  12.  
  13.  
  14.      
  15.     public static void fullMarkImage(String srcImgPath, 
  16.                                  String targetImgPath, 
  17.                                  String iconImgPath, 
  18.                                  float alpha, 
  19.                                  int positionWidth, 
  20.                                  int positionHeight, 
  21.                                  Integer degree, 
  22.                                  String location) { 
  23.         try { 
  24.             // 1、读取源图片 
  25.             Image srcImg = ImageIO.read(new File(srcImgPath)); 
  26.             int srcImgWidth = srcImg.getWidth(null); 
  27.             int srcImgHeight = srcImg.getHeight(null); 
  28.             BufferedImage buffImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); 
  29.  
  30.             // 2、得到画笔对象 
  31.             Graphics2D g = buffImg.createGraphics(); 
  32.             // 3、设置对线段的锯齿状边缘处理 
  33.             g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
  34.             g.drawImage(srcImg.getScaledInstance(srcImgWidth, srcImgHeight, Image.SCALE_SMOOTH), 0, 0, null); 
  35.             // 4、设置水印旋转 
  36.             if (null != degree) { 
  37.                 g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2); 
  38.             } 
  39.             // 5、设置水印文字透明度 
  40.             g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); 
  41.  
  42.             // 6、水印图片的路径 水印图片一般为gif或者png的,这样可设置透明度 
  43.             ImageIcon imgIcon = new ImageIcon(iconImgPath); 
  44.             // 7、得到Image对象。 
  45.             Image iconImg = imgIcon.getImage(); 
  46.             int iconImgWidth = iconImg.getWidth(null); 
  47.             int iconImgHeight = iconImg.getHeight(null); 
  48.  
  49.             int x = 0, y = 0; 
  50.             if (StringUtils.equals(location, "left-top")) { 
  51.                 x = iconImgWidth; 
  52.                 y = iconImgHeight; 
  53.             } else if (StringUtils.equals(location, "right-top")) { 
  54.                 x = srcImgWidth - iconImgWidth - 30; 
  55.                 y = iconImgHeight; 
  56.             } else if (StringUtils.equals(location, "left-bottom")) { 
  57.                 x += iconImgWidth; 
  58.                 y = buffImg.getHeight() - iconImgHeight; 
  59.             } else if (StringUtils.equals(location, "right-bottom")) { 
  60.                 x = srcImgWidth - iconImgWidth - 30; 
  61.                 y = srcImgHeight - iconImgHeight; 
  62.             } else if (StringUtils.equals(location, "center")) { 
  63.                 x = (srcImgWidth - iconImgWidth) / 2; 
  64.                 y = (srcImgHeight - iconImgHeight) / 2; 
  65.             } else { 
  66.                 //自定义位置 
  67.                 x = positionWidth; 
  68.                 y = positionHeight; 
  69.             } 
  70.             g.drawImage(iconImg, x, y, null); 
  71.             g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); 
  72.             // 10、释放资源 
  73.             g.dispose(); 
  74.             // 11、生成图片 
  75.             ImageIO.write(buffImg, "jpg", new File(targetImgPath)); 
  76.             System.out.println("图片完成添加图片水印文字"); 
  77.         } catch (Exception e) { 
  78.             e.printStackTrace(); 
  79.         } 
  80.     } 
  81.  
  82.      
  83.     private static int getWatermarkLength(String text, Graphics2D g) { 
  84.         return g.getFontMetrics(g.getFont()).charsWidth(text.toCharArray(), 0, text.length()); 
  85.     } 
  86.  
  87.     public static void main(String[] args) { 
  88.         String srcImgPath = "/Users/pzblog/Desktop/Jietu.jpg"; //原始文件地址 
  89.         String targetImgPath = "/Users/pzblog/Desktop/Jietu-copy-img.jpg"; //目标文件地址 
  90.         String iconImgPath = "/Users/pzblog/Desktop/1.png"; //图片水印地址 
  91.         float alpha = 0.6f; //水印透明度 
  92.         int positionWidth = 320; //水印横向位置坐标 
  93.         int positionHeight = 450; //水印纵向位置坐标 
  94.         Integer degree = 0; //水印旋转角度 
  95.         String location = "center"; //水印的位置 
  96.         //给图片添加文字水印 
  97.         fullMarkImage(srcImgPath, targetImgPath, iconImgPath, alpha, positionWidth, positionHeight, degree, location); 
  98.     } 

三、踩坑点

以上实现都很简单,但是在实际的实现过程中,却发现了一个巨大的坑,如果你用的iphone手机拍摄的,按照以上代码进行添加水印,会发现图像突然变横了!

例如下图是原图:

按照上面添加水印的处理,得到的图像结果如下:

很明显,图像旋转了90度!

通过不同拍摄角度的反复测试,发现拍摄角度正常,但是经过程序处理之后,有些是需要旋转 90/180/270 度才能回正。

如果想要在正确的位置加上水印,就必须先对图像进行旋转回到原有的角度,然后再添加水印!

那问题来了,我们如何获取其旋转的角度呢?

经过查阅资料,对于图像的拍摄角度信息,有一个专业的名词:EXIF,EXIF是 Exchangeable Image File的缩写,这是一种专门为数码相机照片设定的格式。

这种格式可以用来记录数字照片的属性信息,例如相机的品牌及型号、相片的拍摄时间、拍摄时所设置的光圈大小、快门速度、ISO等等信息。除此之外它还能够记录拍摄数据,以及照片格式化方式。

通过它,我们可以得知图像的旋转角度信息!

下面,我们就一起来了解下采用 Java 语言如何读取图像的 EXIF 信息,包括如何根据 EXIF 信息对图像进行调整以适合用户浏览。

首先添加 EXIF 依赖包

  1.  
  2.     com.drewnoakes 
  3.     metadata-extractor 
  4.     2.16.0 
  5.  

 

然后读取图像的 EXIF 信息

  1. import com.drew.imaging.ImageMetadataReader; 
  2. import com.drew.imaging.ImageProcessingException; 
  3. import com.drew.metadata.Directory; 
  4. import com.drew.metadata.Metadata; 
  5. import com.drew.metadata.Tag; 
  6.  
  7. import java.io.File; 
  8. import java.io.IOException; 
  9.  
  10.  
  11. public class EXIFTest { 
  12.  
  13.     public static void main(String[] args) throws ImageProcessingException, IOException { 
  14.         Metadata metadata = ImageMetadataReader.readMetadata(new File("/Users/pzblog/Desktop/11.jpeg")); 
  15.  
  16.         for (Directory directory : metadata.getDirectories()) { 
  17.             for (Tag tag : directory.getTags()) { 
  18.                 System.out.println(String.format("[%s] - %s = %s"
  19.                         directory.getName(), tag.getTagName(), tag.getDescription())); 
  20.             } 
  21.             if (directory.hasErrors()) { 
  22.                 for (String error : directory.getErrors()) { 
  23.                     System.err.format("ERROR: %s", error); 
  24.                 } 
  25.             } 
  26.         } 
  27.     } 

输入结果:

  1. [JPEG] - Compression Type = Baseline 
  2. [JPEG] - Data Precision = 8 bits 
  3. [JPEG] - Image Height = 1080 pixels 
  4. [JPEG] - Image Width = 1440 pixels 
  5. [JPEG] - Number of Components = 3 
  6. [JPEG] - Component 1 = Y component: Quantization table 0, Sampling factors 2 horiz/2 vert 
  7. [JPEG] - Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert 
  8. [JPEG] - Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert 
  9. [JFIF] - Version = 1.1 
  10. [JFIF] - Resolution Units = none 
  11. [JFIF] - X Resolution = 72 dots 
  12. [JFIF] - Y Resolution = 72 dots 
  13. [JFIF] - Thumbnail Width Pixels = 0 
  14. [JFIF] - Thumbnail Height Pixels = 0 
  15. [Exif IFD0] - Orientation = Right side, top (Rotate 90 CW) 
  16. [Exif SubIFD] - Exif Image Width = 1440 pixels 
  17. [Exif SubIFD] - Exif Image Height = 1080 pixels 
  18. [ICC Profile] - Profile Size = 548 
  19. [ICC Profile] - CMM Type = appl 
  20. [ICC Profile] - Version = 4.0.0 
  21. [ICC Profile] - Class = Display Device 
  22. [ICC Profile] - Color space = RGB  
  23. [ICC Profile] - Profile Connection Space = XYZ  
  24. [ICC Profile] - Profile Date/Time = 2017:07:07 13:22:32 
  25. [ICC Profile] - Signature = acsp 
  26. [ICC Profile] - Primary Platform = Apple Computer, Inc. 
  27. [ICC Profile] - Device manufacturer = APPL 
  28. [ICC Profile] - XYZ values = 0.964 1 0.825 
  29. [ICC Profile] - Tag Count = 10 
  30. [ICC Profile] - Profile Description = Display P3 
  31. [ICC Profile] - Profile Copyright = Copyright Apple Inc., 2017 
  32. [ICC Profile] - Media White Point = (0.9505, 1, 1.0891) 
  33. [ICC Profile] - Red Colorant = (0.5151, 0.2412, 65536) 
  34. [ICC Profile] - Green Colorant = (0.292, 0.6922, 0.0419) 
  35. [ICC Profile] - Blue Colorant = (0.1571, 0.0666, 0.7841) 
  36. [ICC Profile] - Red TRC = para (0x70617261): 32 bytes 
  37. [ICC Profile] - Chromatic Adaptation = sf32 (0x73663332): 44 bytes 
  38. [ICC Profile] - Blue TRC = para (0x70617261): 32 bytes 
  39. [ICC Profile] - Green TRC = para (0x70617261): 32 bytes 
  40. [Photoshop] - Caption Digest = 212 29 140 217 143 0 178 4 233 128 9 152 236 248 66 126 
  41. [Huffman] - Number of Tables = 4 Huffman tables 
  42. [File Type] - Detected File Type Name = JPEG 
  43. [File Type] - Detected File Type Long Name = Joint Photographic Experts Group 
  44. [File Type] - Detected MIME Type = image/jpeg 
  45. [File Type] - Expected File Name Extension = jpg 
  46. [File] - File Name = 11.jpeg 
  47. [File] - File Size = 234344 bytes 
  48. [File] - File Modified Date = 星期日 十一月 07 20:05:52 +08:00 2021 

其中Orientation标签描述的就是图像旋转的角度。

  1. [Exif IFD0] - Orientation = Right side, top (Rotate 90 CW) 

最后,我们可以通过Orientation信息计算出图像对应的旋转角度。

  1. import com.alibaba.fastjson.JSON; 
  2. import com.drew.imaging.jpeg.JpegMetadataReader; 
  3. import com.drew.metadata.Directory; 
  4. import com.drew.metadata.Metadata; 
  5. import com.drew.metadata.Tag; 
  6.  
  7. import java.io.FileInputStream; 
  8. import java.io.IOException; 
  9. import java.io.InputStream; 
  10.  
  11.  
  12. public class TransferImage { 
  13.  
  14.     public static void main(String[] args) throws IOException { 
  15.         String path = "/Users/pzblog/Desktop/11.jpeg"
  16.         int result = getImgRotateAngle(new FileInputStream(path)); 
  17.         System.out.println(result); 
  18.     } 
  19.  
  20.  
  21.     public static int getImgRotateAngle(InputStream inputStream) { 
  22.         int rotateAngle = 0; 
  23.         try { 
  24.             Metadata metadata = JpegMetadataReader.readMetadata(inputStream); 
  25.             Iterable directories = metadata.getDirectories(); 
  26.             for (Directory directory : directories) { 
  27.                 for (Tag tag : directory.getTags()) { 
  28.                     System.out.println(JSON.toJSONString(tag)); 
  29.  
  30.                     int tagType = tag.getTagType(); 
  31.                     //照片拍摄角度信息 
  32.                     if (274 == tagType) { 
  33.                         String description = tag.getDescription(); 
  34.                         //Left side, bottom (Rotate 270 CW) 
  35.                         switch (description) { 
  36.                             //顺时针旋转90度 
  37.                             case "Right side, top (Rotate 90 CW)"
  38.                                 rotateAngle = 90; 
  39.                                 break; 
  40.                             case "Left side, bottom (Rotate 270 CW)"
  41.                                 rotateAngle = 270; 
  42.                                 break; 
  43.                             case "Bottom, right side (Rotate 180)"
  44.                                 rotateAngle = 180; 
  45.                                 break; 
  46.                             default
  47.                                 rotateAngle = 0; 
  48.                                 break; 
  49.                         } 
  50.                     } 
  51.  
  52.                 } 
  53.             } 
  54.             return rotateAngle; 
  55.         } catch (Exception e) { 
  56.             return 0; 
  57.         } 
  58.     } 

输出的旋转角度结果:

  1. 90 

接着通过旋转角度参数,对图像进行回正

  1. import javax.imageio.ImageIO; 
  2. import java.awt.*; 
  3. import java.awt.image.BufferedImage; 
  4. import java.io.File; 
  5. import java.io.IOException; 
  6.  
  7.  
  8. public class RotateImage { 
  9.  
  10.     public static BufferedImage rotate(Image src, int angel) { 
  11.         int src_width = src.getWidth(null); 
  12.         int src_height = src.getHeight(null); 
  13.         // calculate the new image size 
  14.         Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension( 
  15.                 src_width, src_height)), angel); 
  16.  
  17.         BufferedImage res = null
  18.         res = new BufferedImage(rect_des.width, rect_des.height, 
  19.                 BufferedImage.TYPE_INT_RGB); 
  20.         Graphics2D g2 = res.createGraphics(); 
  21.         // transform 
  22.         g2.translate((rect_des.width - src_width) / 2, 
  23.                 (rect_des.height - src_height) / 2); 
  24.         g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2); 
  25.  
  26.         g2.drawImage(src, nullnull); 
  27.         return res; 
  28.     } 
  29.  
  30.     public static Rectangle calcRotatedSize(Rectangle src, int angel) { 
  31.         // if angel is greater than 90 degree, we need to do some conversion 
  32.         if (angel >= 90) { 
  33.             if(angel / 90 % 2 == 1){ 
  34.                 int temp = src.height; 
  35.                 src.height = src.width; 
  36.                 src.width = temp
  37.             } 
  38.             angel = angel % 90; 
  39.         } 
  40.  
  41.         double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2; 
  42.         double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r; 
  43.         double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2; 
  44.         double angel_dalta_width = Math.atan((double) src.height / src.width); 
  45.         double angel_dalta_height = Math.atan((double) src.width / src.height); 
  46.  
  47.         int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha 
  48.                 - angel_dalta_width)); 
  49.         int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha 
  50.                 - angel_dalta_height)); 
  51.         int des_width = src.width + len_dalta_width * 2; 
  52.         int des_height = src.height + len_dalta_height * 2; 
  53.         return new java.awt.Rectangle(new Dimension(des_width, des_height)); 
  54.     } 
  55.  
  56.     public static void main(String[] args) throws IOException { 
  57.         BufferedImage src = ImageIO.read(new File("/Users/pzblog/Desktop/11.jpeg")); 
  58.         BufferedImage des = RotateImage.rotate(src, 90); 
  59.         ImageIO.write(des, "jpg", new File("/Users/pzblog/Desktop/11-rotate.jpeg")); 
  60.     } 

最后给回正后的图像添加水印

  1. public static void main(String[] args) { 
  2.     String srcImgPath = "/Users/pzblog/Desktop/11-rotate.jpeg"; //原始文件地址 
  3.     String targetImgPath = "/Users/pzblog/Desktop/1-rotate-copy.jpg"; //目标文件地址 
  4.     String text = "复 印 无 效"; //水印文字内容 
  5.     Color color = Color.red; //水印文字颜色 
  6.     Font font = new Font("宋体", Font.BOLD, 60); //水印文字字体 
  7.     float alpha = 0.4f; //水印透明度 
  8.     int positionWidth = 320; //水印横向位置坐标 
  9.     int positionHeight = 450; //水印纵向位置坐标 
  10.     Integer degree = -30; //水印旋转角度 
  11.     String location = "center"; //水印的位置 
  12.     //给图片添加文字水印 
  13.     markImage(srcImgPath, targetImgPath, text, color, font, alpha, positionWidth, positionHeight, degree, location); 

输入结果:

添加水印的结果与预期一致!

四、小结

 

给图像添加水印最坑的地方就上面介绍的那个位置,如果是网络截图的照片,基本添加的结果与预期一致,但是采用手机拍摄的,很有可能会发生旋转,因此需要采用一些手法,先获取对应的图像旋转角度,然后进行回正,最后添加水印,保证与预期结果一致!

 

来源: Java极客技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯