123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- using OpenCvSharp;
- namespace Masuit.Tools.DigitalWatermarker.Test;
- public class DigitalWatermarkerTests : IDisposable
- {
- private readonly string _testImageDirectory;
- private readonly string _sourceImagePath;
- private readonly string _watermarkImagePath;
- private readonly Mat _sourceImage;
- private readonly Mat _watermarkImage;
- public DigitalWatermarkerTests()
- {
- // 创建测试目录
- _testImageDirectory = Path.Combine(Path.GetTempPath(), "DigitalWatermarkerTests", Guid.NewGuid().ToString());
- Directory.CreateDirectory(_testImageDirectory);
- // 创建测试图像文件路径
- _sourceImagePath = Path.Combine(_testImageDirectory, "source.jpg");
- _watermarkImagePath = Path.Combine(_testImageDirectory, "watermark.png");
- // 创建测试用的源图像 (512x512 彩色图像)
- _sourceImage = CreateTestSourceImage();
- // 创建测试用的水印图像 (64x64 二值图像)
- _watermarkImage = CreateTestWatermarkImage();
- // 保存测试图像到文件
- Cv2.ImWrite(_sourceImagePath, _sourceImage);
- Cv2.ImWrite(_watermarkImagePath, _watermarkImage);
- }
- public void Dispose()
- {
- _sourceImage?.Dispose();
- _watermarkImage?.Dispose();
- // 清理测试文件
- if (Directory.Exists(_testImageDirectory))
- {
- Directory.Delete(_testImageDirectory, true);
- }
- }
- #region 测试Mat对象方法
- [Fact]
- public void EmbedWatermark_WithValidMatObjects_ShouldReturnWatermarkedImage()
- {
- // Act
- using var result = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, _watermarkImage);
- // Assert
- Assert.NotNull(result);
- Assert.False(result.Empty());
- Assert.Equal(_sourceImage.Size(), result.Size());
- Assert.Equal(_sourceImage.Type(), result.Type());
- }
- [Fact]
- public void EmbedWatermark_WithEmptySource_ShouldThrowArgumentException()
- {
- // Arrange
- using var emptyMat = new Mat();
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(emptyMat, _watermarkImage));
- Assert.Contains("source is empty", exception.Message);
- }
- [Fact]
- public void EmbedWatermark_WithEmptyWatermark_ShouldThrowArgumentException()
- {
- // Arrange
- using var emptyMat = new Mat();
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, emptyMat));
- Assert.Contains("watermark is empty", exception.Message);
- }
- [Fact]
- public void ExtractWatermark_WithValidImage_ShouldReturnWatermark()
- {
- // Arrange
- using var watermarkedImage = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, _watermarkImage);
- // Act
- using var extractedWatermark = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(watermarkedImage);
- // Assert
- Assert.NotNull(extractedWatermark);
- Assert.False(extractedWatermark.Empty());
- Assert.Equal(MatType.CV_8U, extractedWatermark.Type());
- }
- [Fact]
- public void ExtractWatermark_WithEmptyImage_ShouldThrowArgumentException()
- {
- // Arrange
- using var emptyMat = new Mat();
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(emptyMat));
- Assert.Contains("image is empty", exception.Message);
- }
- #endregion 测试Mat对象方法
- #region 测试文件路径方法
- [Fact]
- public void EmbedWatermark_WithValidFilePaths_ShouldReturnWatermarkedImage()
- {
- // Act
- using var result = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImagePath, _watermarkImagePath);
- // Assert
- Assert.NotNull(result);
- Assert.False(result.Empty());
- Assert.Equal(_sourceImage.Size(), result.Size());
- Assert.Equal(_sourceImage.Type(), result.Type());
- }
- [Fact]
- public void EmbedWatermark_WithNullSourcePath_ShouldThrowArgumentException()
- {
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(null, _watermarkImagePath));
- Assert.Contains("图片路径不能为空", exception.Message);
- }
- [Fact]
- public void EmbedWatermark_WithEmptySourcePath_ShouldThrowArgumentException()
- {
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark("", _watermarkImagePath));
- Assert.Contains("图片路径不能为空", exception.Message);
- }
- [Fact]
- public void EmbedWatermark_WithNullWatermarkPath_ShouldThrowArgumentException()
- {
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImagePath, null));
- Assert.Contains("水印图片路径不能为空", exception.Message);
- }
- [Fact]
- public void EmbedWatermark_WithNonExistentSourceFile_ShouldThrowFileNotFoundException()
- {
- // Act & Assert
- var exception = Assert.Throws<FileNotFoundException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark("nonexistent.jpg", _watermarkImagePath));
- Assert.Contains("文件不存在", exception.Message);
- }
- [Fact]
- public void EmbedWatermark_WithNonExistentWatermarkFile_ShouldThrowFileNotFoundException()
- {
- // Act & Assert
- var exception = Assert.Throws<FileNotFoundException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImagePath, "nonexistent.png"));
- Assert.Contains("文件不存在", exception.Message);
- }
- [Fact]
- public void ExtractWatermark_WithValidFilePath_ShouldReturnWatermark()
- {
- // Arrange
- using var watermarkedImage = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImagePath, _watermarkImagePath);
- var watermarkedImagePath = Path.Combine(_testImageDirectory, "watermarked.jpg");
- Cv2.ImWrite(watermarkedImagePath, watermarkedImage);
- // Act
- using var extractedWatermark = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(watermarkedImagePath);
- // Assert
- Assert.NotNull(extractedWatermark);
- Assert.False(extractedWatermark.Empty());
- }
- [Fact]
- public void ExtractWatermark_WithNullPath_ShouldThrowArgumentException()
- {
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark((string)null!));
- Assert.Contains("路径不能为空", exception.Message);
- }
- [Fact]
- public void ExtractWatermark_WithNonExistentFile_ShouldThrowFileNotFoundException()
- {
- // Act & Assert
- var exception = Assert.Throws<FileNotFoundException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark("nonexistent.jpg"));
- Assert.Contains("文件不存在", exception.Message);
- }
- #endregion 测试文件路径方法
- #region 测试Stream方法
- [Fact]
- public void EmbedWatermark_WithValidStreams_ShouldReturnWatermarkedImage()
- {
- // Arrange
- using var sourceStream = new MemoryStream();
- using var watermarkStream = new MemoryStream();
- Cv2.ImEncode(".jpg", _sourceImage, out var sourceBytes);
- Cv2.ImEncode(".png", _watermarkImage, out var watermarkBytes);
- sourceStream.Write(sourceBytes);
- watermarkStream.Write(watermarkBytes);
- sourceStream.Position = 0;
- watermarkStream.Position = 0;
- // Act
- using var result = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(sourceStream, watermarkStream);
- // Assert
- Assert.NotNull(result);
- Assert.False(result.Empty());
- Assert.Equal(_sourceImage.Size(), result.Size());
- Assert.Equal(_sourceImage.Type(), result.Type());
- }
- [Fact]
- public void EmbedWatermark_WithNullSourceStream_ShouldThrowArgumentNullException()
- {
- // Arrange
- using var watermarkStream = new MemoryStream();
- // Act & Assert
- Assert.Throws<ArgumentNullException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(null, watermarkStream));
- }
- [Fact]
- public void EmbedWatermark_WithNullWatermarkStream_ShouldThrowArgumentNullException()
- {
- // Arrange
- using var sourceStream = new MemoryStream();
- // Act & Assert
- Assert.Throws<ArgumentNullException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(sourceStream, null));
- }
- [Fact]
- public void ExtractWatermark_WithValidStream_ShouldReturnWatermark()
- {
- // Arrange
- using var watermarkedImage = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, _watermarkImage);
- using var imageStream = new MemoryStream();
- Cv2.ImEncode(".jpg", watermarkedImage, out var imageBytes);
- imageStream.Write(imageBytes);
- imageStream.Position = 0;
- // Act
- using var extractedWatermark = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(imageStream);
- // Assert
- Assert.NotNull(extractedWatermark);
- Assert.False(extractedWatermark.Empty());
- }
- [Fact]
- public void ExtractWatermark_WithNullStream_ShouldThrowArgumentNullException()
- {
- // Act & Assert
- Assert.Throws<ArgumentNullException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark((Stream)null!));
- }
- [Fact]
- public void ExtractWatermark_WithInvalidImageStream_ShouldThrowArgumentException()
- {
- // Arrange
- using var invalidStream = new MemoryStream(new byte[] { 1, 2, 3, 4, 5 });
- // Act & Assert
- var exception = Assert.Throws<ArgumentException>(() =>
- Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(invalidStream));
- Assert.Contains("stream不能解析为图像", exception.Message);
- }
- #endregion 测试Stream方法
- #region 集成测试
- [Fact]
- public void WatermarkRoundTrip_ShouldPreserveWatermarkPattern()
- {
- // Arrange - 创建一个有明确模式的水印
- using var patternWatermark = CreatePatternWatermark();
- // Act - 嵌入并提取水印
- using var watermarkedImage = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, patternWatermark);
- using var extractedWatermark = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(watermarkedImage);
- // Assert - 验证提取的水印不为空且有合理的尺寸
- Assert.NotNull(extractedWatermark);
- Assert.False(extractedWatermark.Empty());
- Assert.True(extractedWatermark.Rows > 0);
- Assert.True(extractedWatermark.Cols > 0);
- }
- [Fact]
- public void WatermarkShouldBeRobustToJpegCompression()
- {
- // Arrange
- using var watermarkedImage = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.EmbedWatermark(_sourceImage, _watermarkImage);
- // 模拟JPEG压缩
- var compressionParams = new int[] { (int)ImwriteFlags.JpegQuality, 75 };
- Cv2.ImEncode(".jpg", watermarkedImage, out var compressedBytes, compressionParams);
- using var compressedImage = Cv2.ImDecode(compressedBytes, ImreadModes.Color);
- // Act
- using var extractedWatermark = Masuit.Tools.DigtalWatermarker.DigitalWatermarker.ExtractWatermark(compressedImage);
- // Assert
- Assert.NotNull(extractedWatermark);
- Assert.False(extractedWatermark.Empty());
- }
- #endregion 集成测试
- #region 辅助方法
- private static Mat CreateTestSourceImage()
- {
- var image = new Mat(512, 512, MatType.CV_8UC3);
- // 创建渐变背景
- for (int y = 0; y < image.Rows; y++)
- {
- for (int x = 0; x < image.Cols; x++)
- {
- byte intensity = (byte)(128 + (x + y) % 128);
- image.Set(y, x, new Vec3b(intensity, (byte)(255 - intensity), (byte)(intensity / 2)));
- }
- }
- return image;
- }
- private static Mat CreateTestWatermarkImage()
- {
- var watermark = new Mat(64, 64, MatType.CV_8UC1, Scalar.Black);
- // 创建简单的棋盘格模式
- for (int y = 0; y < watermark.Rows; y++)
- {
- for (int x = 0; x < watermark.Cols; x++)
- {
- if ((x / 8 + y / 8) % 2 == 0)
- {
- watermark.Set(y, x, (byte)255);
- }
- }
- }
- return watermark;
- }
- private static Mat CreatePatternWatermark()
- {
- var watermark = new Mat(32, 32, MatType.CV_8UC1, Scalar.Black);
- // 创建十字形模式
- int center = 16;
- for (int i = 0; i < 32; i++)
- {
- watermark.Set(center, i, (byte)255); // 水平线
- watermark.Set(i, center, (byte)255); // 垂直线
- }
- return watermark;
- }
- #endregion 辅助方法
- }
|