Старий спосіб був болючим

Уявіть, що співробітник з комплаєнсу має перевірити, чи кожен контракт у спільному диску містить слово “CONFIDENTIAL” та логотип компанії на кожній сторінці. Поточний процес виглядає так:

  1. Відкрити файл у переглядачі.
  2. Перегортати кожну сторінку в пошуках фрази або зображення.
  3. Записувати нотатки у електронну таблицю.
  4. Повторювати для тисяч 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