Старий спосіб був болючим
Уявіть, що співробітник з комплаєнсу має перевірити, чи кожен контракт у спільному диску містить слово “CONFIDENTIAL” та логотип компанії на кожній сторінці. Поточний процес виглядає так:
- Відкрити файл у переглядачі.
- Перегортати кожну сторінку в пошуках фрази або зображення.
- Записувати нотатки у електронну таблицю.
- Повторювати для тисяч PDF‑файлів, Word‑документів та презентацій.
Одне пропущене водяне позначення може викликати дорогий перегляд, а ручна праця легко перевищує 8 годин на тиждень для невеликої команди. До того ж, обернений текст, розділені слова або логотипи, збережені як зображення, часто залишаються непоміченими, залишаючи організацію вразливою.
Є кращий спосіб
GroupDocs.Watermark for .NET усуває кожен крок, що базується на здогадках. Його форматно‑агностичний движок може читати понад 100 типів документів, знаходити текстові, графічні та навіть стилізовані водяні знаки і надавати всю відповідну метадану через чистий API. Наведений нижче підручник показує, як кілька стислих фрагментів коду замінюють ручний цикл автоматизованим, повторюваним робочим процесом.
Вимоги
- .NET 6.0 або новіша версія.
- GroupDocs.Watermark пакет NuGet (
dotnet add package GroupDocs.Watermark). - (Необов’язково) тимчасова ліцензія – дивіться посилання в кінці статті.
Новий спосіб: Автоматизований аудит водяних знаків
Нижче розглядаються чотири основні операції. Кожен блок – це самодостатній приклад, який можна вставити у консольний застосунок, крок CI або фонову службу.
Крок 1 – Сканування всіх водяних знаків
Спочатку потрібен повний інвентар. Метод Search() повертає колекцію, де кожен запис містить текст (або зображення), розташування, кут обертання, номер сторінки та розмір зображення.
using (var wk = new Watermarker(filePath))
{
var all = wk.Search();
Console.WriteLine($"Found {all.Count} watermark(s) in " +
$"'{Path.GetFileName(filePath)}':");
int i = 0;
foreach (var wm in all)
{
Console.WriteLine($" #{++i}: {(wm.Text ?? "[image]")} ");
Console.WriteLine($" Page {wm.PageNumber}, " +
$"Pos X={wm.X}, Y={wm.Y}, Rot={wm.RotateAngle}°");
Console.WriteLine($" Size {wm.Width}×{wm.Height}");
if (wm.ImageData != null)
Console.WriteLine($" Image bytes {wm.ImageData.Length}");
}
}
Ключовий момент: цикл виконується менше секунди для типового 50‑сторінкового PDF.
Крок 2 – Перевірка необхідного текстового водяного знака
Політики комплаєнсу часто вимагають конкретну фразу (наприклад, “CONFIDENTIAL”). TextSearchCriteria з SkipUnreadableCharacters автоматично обробляє розділений або обернений текст.
using (var wk = new Watermarker(filePath))
{
var crit = new TextSearchCriteria(expectedPhrase);
crit.SkipUnreadableCharacters = true; // ігнорувати артефакти OCR
var hits = wk.Search(crit);
bool ok = hits.Count > 0;
Console.WriteLine($" [{(ok ? "PASS" : "FAIL")}] " +
$"'{expectedPhrase}' found {hits.Count} time(s)");
return ok;
}
Метод повертає true, коли фраза зустрічається хоча б один раз, даючи миттєвий прапорець PASS/FAIL.
Крок 3 – Перевірка логотипу компанії
Логотипи зберігаються як растрові зображення, і їх вигляд може трохи змінюватися через стиснення. ImageDctHashSearchCriteria створює перцептивний хеш референтного логотипу і порівнює його з налаштовуваною толерантністю.
using (var wk = new Watermarker(filePath))
{
var crit = new ImageDctHashSearchCriteria(logoPath);
crit.MaxDifference = 0.9; // допускає помірне масштабування / зміну кольору
var matches = wk.Search(crit);
bool ok = matches.Count > 0;
Console.WriteLine($" [{(ok ? "PASS" : "FAIL")}] " +
$"logo instances: {matches.Count}");
return ok;
}
Навіть копія логотипу низької роздільної здатності буде розпізнана.
Крок 4 – Запуск повного звіту про відповідність
Реальні політики поєднують кілька вимог. Перший блок перевіряє чотири правила форматування — наявність тексту, шрифт, розмір і жирний стиль — кожне комбінує TextSearchCriteria з TextFormattingSearchCriteria через .And():
using (var wk = new Watermarker(filePath))
{
int passed = 0, failed = 0;
var txtCrit = new TextSearchCriteria(expectedPhrase);
bool hasText = wk.Search(txtCrit).Count > 0;
Console.WriteLine($" [{(hasText ? "PASS" : "FAIL")}] Text present");
if (hasText) passed++; else failed++;
var fontCrit = new TextFormattingSearchCriteria { FontName = expFont };
bool hasFont = wk.Search(txtCrit.And(fontCrit)).Count > 0;
Console.WriteLine($" [{(hasFont ? "PASS" : "FAIL")}] Font {expFont}");
if (hasFont) passed++; else failed++;
var sizeCrit = new TextFormattingSearchCriteria { MinFontSize = minSize };
bool hasSize = wk.Search(txtCrit.And(sizeCrit)).Count > 0;
Console.WriteLine($" [{(hasSize ? "PASS" : "FAIL")}] Size >= {minSize}");
if (hasSize) passed++; else failed++;
var boldCrit = new TextFormattingSearchCriteria { FontBold = true };
bool hasBold = wk.Search(txtCrit.And(boldCrit)).Count > 0;
Console.WriteLine($" [{(hasBold ? "PASS" : "FAIL")}] Bold formatting");
if (hasBold) passed++; else failed++;
П’яте правило перевіряє покриття сторінок — водяний знак має бути на кожній сторінці. Нарешті, підсумок агрегує всі результати:
var perPage = wk.Search(txtCrit);
var pages = new HashSet<int>();
foreach (var wm in perPage)
if (wm.PageNumber.HasValue) pages.Add(wm.PageNumber.Value);
var allPages = wk.Search();
int max = 0;
foreach (var wm in allPages)
max = Math.Max(max, wm.PageNumber ?? 0);
bool full = max > 0 && pages.Count == max;
Console.WriteLine($" [{(full ? "PASS" : "FAIL")}] " +
$"Pages covered {pages.Count}/{max}");
if (full) passed++; else failed++;
string verdict = failed == 0 ? "COMPLIANT" : "NON-COMPLIANT";
Console.WriteLine($"\nResult: {verdict} " +
$"({passed} passed, {failed} failed)");
}
Звіт готовий до експорту у JSON, CSV або безпосередньо в систему тикетів.
Порівняння: До та Після
| Ручний огляд | Автоматизований аудит | |
|---|---|---|
| Час | Години за пакет | Секунди за файл |
| Точність | Схильність до людських помилок | Детермінований API |
| Масштабованість | Обмежено кількома документами | Обробляє тисячі |
| Необхідний код | Немає (але трудомістко) | ~30 рядків C# |
| Вихід | Лише візуальна перевірка | Структурований звіт PASS/FAIL |
Контраст вражає: те, що раніше займало цілий робочий день, тепер виконується як фонове завдання.
Приклад з реального світу: Бібліотека юридичних контрактів
Юридична фірма зберігає 15 000 контрактів у спільній папці. Їхня політика вимагає фразу “CONFIDENTIAL – CLIENT XYZ” та печатку фірми на кожній сторінці. Інтегрувавши наведені вище фрагменти у нічний PowerShell‑скрипт, фірма досягла:
- 100 % виявлення відсутніх позначок (раніше 8 % пропускалися).
- Нуль ручних годин витрачено на аудит.
- А журнал аудиту збережено у внутрішньому списку SharePoint для майбутніх регуляторних перевірок.
// Example of the nightly job entry point
var folder = @"\\fileserver\Contracts";
foreach (var pdf in Directory.GetFiles(folder, "*.pdf", SearchOption.AllDirectories))
{
// reuse the methods from steps 1‑4
ScanAll(pdf);
VerifyText(pdf, "CONFIDENTIAL – CLIENT XYZ");
VerifyLogo(pdf, @"C:\Logos\firm-seal.png");
RunReport(pdf);
}
Скрипт працює без нагляду і щодня вранці надсилає підсумковий лист електронною поштою.
Що ще можна зробити з GroupDocs.Watermark?
Окрім аудиту, приклад проекту показує, як замінювати та видаляти водяні знаки програмно. Нижче наведені скріншоти, які демонструють обидві операції на реальному PDF:
Інші сценарії, які можна реалізувати за допомогою того ж API:
- Додати невидимі відстежувальні водяні знаки, які вбудовують унікальний ідентифікатор для відстеження витоків.
- Масово замінити застарілі логотипи у всьому архіві.
- Створювати готові до PDF сертифікати відповідності після успішного аудиту.
- Інтегрувати з Azure Functions або AWS Lambda для безсерверної обробки.
Кожен сценарій використовує один і той же базовий API – достатньо лише змінити критерії пошуку або тип водяного знака.
Висновок
Те, що колись вимагало від команди перегортати сторінки, робити нотатки і ризикувати пропуском позначок, тепер стало кількома секундами коду, що генерує аудиторський звіт PASS/FAIL. З GroupDocs.Watermark for .NET ви отримуєте:
- Повний огляд кожного водяного знака.
- Надійне виявлення тексту, стилізованого тексту та логотипів.
- Автоматичне формування звітів про відповідність.
- Можливість оновлювати або видаляти водяні знаки програмно.
Спробуйте і перетворіть процес комплаєнсу водяних знаків з головного болю на повторювану службу.
Наступні кроки
- Спробуйте безкоштовну пробну версію API – отримайте тимчасову ліцензію тут: Temp License
- Прочитайте повну документацію для розширених опцій: Docs
- Ознайомтеся з довідником .NET API для всіх класів і методів: API Reference
- Клонувати приклад проекту на GitHub, щоб побачити повний консольний додаток: GitHub Samples
- Задавайте питання або діліться своїм випадком використання на форумі спільноти: Forum