Skip to content

Instantly share code, notes, and snippets.

@GroupDocsGists
Created April 19, 2026 08:21
Show Gist options
  • Select an option

  • Save GroupDocsGists/b4904f54bb37b56c4e1124aec88822c0 to your computer and use it in GitHub Desktop.

Select an option

Save GroupDocsGists/b4904f54bb37b56c4e1124aec88822c0 to your computer and use it in GitHub Desktop.
Examples demonstrating scanning, verification, compliance reporting, and management of watermarks using GroupDocs.Watermark for .NET.

Comprehensive Watermark Audit Toolkit in .NET

This gist provides a collection of concise .NET examples that show how to audit, verify, replace, remove, and track watermarks in documents using GroupDocs.Watermark.

📦 Prerequisites

🔧 Key Capabilities

  • Scan and list all watermarks in a document
  • Verify text or image watermarks
  • Run a multi‑rule compliance report
  • Replace or remove watermarks based on custom criteria
  • Add and detect hidden tracking watermarks for leak detection

📁 Code Examples

See the following example files:

📋 How to Use

  1. Install the GroupDocs.Watermark NuGet package.
  2. Prepare the input document path and any parameters required by the example.
  3. Create a Watermarker instance as shown in each snippet.
  4. Call the relevant API methods (Search, Add, Save, etc.).
  5. Review the console output or the saved document to see the results.

📎 Related Articles

🔚 Conclusion

These samples illustrate how to audit, verify, and manage watermarks with GroupDocs.Watermark for .NET. For the full API reference, detailed guides, and a free trial, visit the product documentation site.

using (Watermarker watermarker = new Watermarker(filePath))
{
string trackingText = $"ID:{recipientId}";
var watermark = new TextWatermark(trackingText, new Font("Arial", 6))
{
ForegroundColor = Color.FromArgb(5, 200, 200, 200),
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Bottom,
Opacity = 0.02
};
watermarker.Add(watermark);
watermarker.Save(outputPath);
Console.WriteLine($" Tracking watermark added for recipient '{recipientId}'");
}
using (Watermarker watermarker = new Watermarker(filePath))
{
Regex pattern = new Regex(@"ID:[\w-]+");
TextSearchCriteria criteria = new TextSearchCriteria(pattern);
PossibleWatermarkCollection found = watermarker.Search(criteria);
if (found.Count > 0)
{
string trackingId = found[0].Text;
Console.WriteLine($" Tracking watermark found: {trackingId}");
return trackingId;
}
Console.WriteLine(" No tracking watermark detected");
return null;
}
using (Watermarker watermarker = new Watermarker(filePath))
{
TextSearchCriteria textCriteria = new TextSearchCriteria(watermarkText);
TextFormattingSearchCriteria formatCriteria = new TextFormattingSearchCriteria();
formatCriteria.FontName = "Arial";
formatCriteria.MinFontSize = 15;
formatCriteria.FontBold = true;
SearchCriteria combinedCriteria = textCriteria.And(formatCriteria);
PossibleWatermarkCollection watermarks = watermarker.Search(combinedCriteria);
Console.WriteLine($" Found {watermarks.Count} watermark(s) matching criteria");
watermarks.Clear();
watermarker.Save(outputPath);
Console.WriteLine($" Removed watermarks and saved to '{Path.GetFileName(outputPath)}'");
}
using (Watermarker watermarker = new Watermarker(filePath))
{
TextSearchCriteria criteria = new TextSearchCriteria(oldText, false);
PossibleWatermarkCollection watermarks = watermarker.Search(criteria);
Console.WriteLine($" Found {watermarks.Count} watermark(s) with text '{oldText}'");
foreach (PossibleWatermark watermark in watermarks)
{
try
{
watermark.FormattedTextFragments.Clear();
watermark.FormattedTextFragments.Add(
newText,
new Font("Arial", 19, FontStyle.Bold),
Color.DarkBlue,
Color.Transparent);
}
catch (Exception ex)
{
Console.WriteLine($" Warning: Could not edit entity: {ex.Message}");
}
}
watermarker.Save(outputPath);
Console.WriteLine($" Saved updated document to '{Path.GetFileName(outputPath)}'");
}
using (Watermarker watermarker = new Watermarker(filePath))
{
int passed = 0, failed = 0;
// Rule 1: expected text must be present
var textCriteria = new TextSearchCriteria(expectedText);
var textMatches = watermarker.Search(textCriteria);
bool hasText = textMatches.Count > 0;
Console.WriteLine(
$" [{(hasText ? \"PASS\" : \"FAIL\")}] " +
$"Text '{expectedText}' present: {textMatches.Count} match(es)");
if (hasText) passed++; else failed++;
// Rule 2: text must use the expected font
var fontCriteria = new TextFormattingSearchCriteria();
fontCriteria.FontName = expectedFont;
var fontMatches = watermarker.Search(textCriteria.And(fontCriteria));
bool hasFont = fontMatches.Count > 0;
Console.WriteLine(
$" [{(hasFont ? \"PASS\" : \"FAIL\")}] " +
$"Font '{expectedFont}': {fontMatches.Count} match(es)");
if (hasFont) passed++; else failed++;
// Rule 3: minimum font size
var sizeCriteria = new TextFormattingSearchCriteria();
sizeCriteria.MinFontSize = expectedMinSize;
var sizeMatches = watermarker.Search(textCriteria.And(sizeCriteria));
bool hasSize = sizeMatches.Count > 0;
Console.WriteLine(
$" [{(hasSize ? \"PASS\" : \"FAIL\")}] " +
$"Min font size >= {expectedMinSize}: {sizeMatches.Count} match(es)");
if (hasSize) passed++; else failed++;
// Rule 4: bold formatting
var boldCriteria = new TextFormattingSearchCriteria();
boldCriteria.FontBold = expectedBold;
var boldMatches = watermarker.Search(textCriteria.And(boldCriteria));
bool hasBold = boldMatches.Count > 0;
Console.WriteLine(
$" [{(hasBold ? \"PASS\" : \"FAIL\")}] " +
$"Bold formatting: {boldMatches.Count} match(es)");
if (hasBold) passed++; else failed++;
// Rule 5: watermark on every page
var allWatermarks = watermarker.Search(textCriteria);
var pages = new HashSet<int>();
foreach (PossibleWatermark wm in allWatermarks)
if (wm.PageNumber.HasValue)
pages.Add(wm.PageNumber.Value);
var allItems = watermarker.Search();
int maxPage = 0;
foreach (PossibleWatermark wm in allItems)
{
int pg = wm.PageNumber ?? 0;
if (pg > maxPage)
maxPage = pg;
}
int totalPages = Math.Max(maxPage, pages.Count);
bool allPages = totalPages > 0 && pages.Count >= totalPages;
Console.WriteLine(
$" [{(allPages ? \"PASS\" : \"FAIL\")}] " +
$"Watermarked pages: {pages.Count}/{totalPages}");
if (allPages) passed++; else failed++;
string verdict = failed == 0 ? "COMPLIANT" : "NON-COMPLIANT";
Console.WriteLine($"\n Result: {verdict} ({passed} passed, {failed} failed)");
}
using (Watermarker watermarker = new Watermarker(filePath))
{
PossibleWatermarkCollection possibleWatermarks = watermarker.Search();
Console.WriteLine($"Found {possibleWatermarks.Count} possible watermark(s) " +
$"in '{Path.GetFileName(filePath)}':\n");
int index = 0;
foreach (PossibleWatermark watermark in possibleWatermarks)
{
Console.WriteLine($" Watermark #{++index}");
Console.WriteLine($" Text: {watermark.Text ?? \"(image)\"}");
Console.WriteLine($" Position: X={watermark.X}, Y={watermark.Y}");
Console.WriteLine($" Size: {watermark.Width} x {watermark.Height}");
Console.WriteLine($" Rotation: {watermark.RotateAngle} degrees");
Console.WriteLine($" Page: {watermark.PageNumber}");
if (watermark.ImageData != null)
{
Console.WriteLine($" Image data: {watermark.ImageData.Length} bytes");
}
}
}
using (Watermarker watermarker = new Watermarker(filePath))
{
ImageSearchCriteria criteria = new ImageDctHashSearchCriteria(expectedLogoPath);
criteria.MaxDifference = 0.9;
PossibleWatermarkCollection found = watermarker.Search(criteria);
bool passed = found.Count > 0;
Console.WriteLine($" [{(passed ? \"PASS\" : \"FAIL\")}] " +
$"logo match: {found.Count} instance(s)");
return passed;
}
using (Watermarker watermarker = new Watermarker(filePath))
{
TextSearchCriteria criteria = new TextSearchCriteria(expectedText);
criteria.SkipUnreadableCharacters = true;
PossibleWatermarkCollection found = watermarker.Search(criteria);
bool passed = found.Count > 0;
Console.WriteLine($" [{(passed ? \"PASS\" : \"FAIL\")}] " +
$"expected '{expectedText}', found {found.Count} match(es)");
return passed;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment