Stara Metoda Była Bolesna

Wyobraź sobie pracownika ds. zgodności, któremu powierzono weryfikację, czy każdy kontrakt w udostępnionym dysku zawiera słowo „CONFIDENTIAL” oraz logo firmy na każdej stronie. Obecny proces wygląda tak:

  1. Otwórz plik w przeglądarce.
  2. Przeglądaj kolejne strony, szukając frazy lub obrazu.
  3. Zapisuj notatki w arkuszu kalkulacyjnym.
  4. Powtarzaj dla tysięcy plików PDF, Word i prezentacji.

Jedno pominięte znaki wodne może wywołać kosztowną kontrolę, a ręczny wysiłek łatwo przekracza 8 godzin tygodniowo dla małego zespołu. Co więcej, obracany tekst, podzielone słowa lub loga zapisane jako obrazy często umykają ludzkim oczom, pozostawiając organizację narażoną.

Jest Lepszy Sposób

GroupDocs.Watermark for .NET eliminuje wszystkie kroki zgadywania. Jego silnik niezależny od formatu potrafi odczytać ponad 100 typów dokumentów, zlokalizować tekst, obraz i nawet stylizowane znaki wodne oraz udostępnić wszystkie istotne metadane poprzez przejrzyste API. Poniższy samouczek pokazuje, jak kilka zwięzłych fragmentów kodu zastępuje ręczną pętlę automatycznym, powtarzalnym przepływem pracy.

Wymagania wstępne

  • .NET 6.0 lub nowszy.
  • Pakiet NuGet GroupDocs.Watermark (dotnet add package GroupDocs.Watermark).
  • (Opcjonalnie) tymczasowa licencja – zobacz link na końcu tego artykułu.

Nowy Sposób: Zautomatyzowany Audyt Znaków Wodnych

Poniżej przechodzimy przez cztery podstawowe operacje. Każdy blok jest samodzielnym przykładem, który możesz wkleić do aplikacji konsolowej, kroku CI lub usługi w tle.

Krok 1 – Skanuj Wszystkie Znaki Wodne

Najpierw potrzebujemy pełnego spisu. Metoda Search() zwraca kolekcję, w której każdy element zawiera tekst (lub obraz), położenie, obrót, numer strony oraz rozmiar surowego obrazu.

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}");
    }
}

Kluczowy punkt: Pętla działa w mniej niż sekundę dla typowego 50‑stronicowego PDF‑a.

Krok 2 – Zweryfikuj Wymagany Tekstowy Znak Wodny

Polityki zgodności często wymagają konkretnej frazy (np. „CONFIDENTIAL”). TextSearchCriteria z włączonym SkipUnreadableCharacters automatycznie radzi sobie z podzielonym lub obróconym tekstem.

using (var wk = new Watermarker(filePath))
{
    var crit = new TextSearchCriteria(expectedPhrase);
    crit.SkipUnreadableCharacters = true;   // ignoruj artefakty OCR
    var hits = wk.Search(crit);
    bool ok = hits.Count > 0;
    Console.WriteLine($"  [{(ok ? "PASS" : "FAIL")}] " +
        $"'{expectedPhrase}' found {hits.Count} time(s)");
    return ok;
}

Metoda zwraca true, gdy fraza pojawi się przynajmniej raz, dając natychmiastowy znacznik PASS/FAIL.

Krok 3 – Zweryfikuj Logo Firmowe

Loga są przechowywane jako obrazy rastrowe, a ich wygląd może nieco różnić się z powodu kompresji. ImageDctHashSearchCriteria tworzy percepcyjny hash referencyjnego logo i dopasowuje go przy użyciu konfigurowalnej tolerancji.

using (var wk = new Watermarker(filePath))
{
    var crit = new ImageDctHashSearchCriteria(logoPath);
    crit.MaxDifference = 0.9;   // toleruj umiarkowane skalowanie / zmianę koloru
    var matches = wk.Search(crit);
    bool ok = matches.Count > 0;
    Console.WriteLine($"  [{(ok ? "PASS" : "FAIL")}] " +
        $"logo instances: {matches.Count}");
    return ok;
}

Nawet niskiej rozdzielczości kopia logo zostanie rozpoznana.

Krok 4 – Wykonaj Pełny Raport Zgodności

W praktyce polityki łączą kilka wymagań. Pierwszy blok sprawdza cztery reguły formatowania — obecność tekstu, czcionkę, rozmiar i pogrubienie — każda łączy TextSearchCriteria z TextFormattingSearchCriteria przy pomocy .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++;

Piąta reguła weryfikuje pokrycie stron — znak wodny musi występować na każdej stronie. Na koniec werdykt sumuje wszystkie wyniki:

    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)");
}

Raport można wyeksportować jako JSON, CSV lub bezpośrednio przekazać do systemu zgłoszeniowego.


Rzut Okiem: Przed vs. Po

Przegląd ręczny Audyt automatyczny
Czas Godziny na partię Sekundy na plik
Dokładność Błędy ludzkie Deterministyczne API
Skalowalność Ograniczona do kilku dokumentów Obsługuje tysiące
Wymagany kod Brak (ale praca ręczna) ~30 linii C#
Wynik Tylko wizualna inspekcja Strukturalny raport PASS/FAIL

Kontrast jest wyraźny: to, co kiedyś zajmowało cały dzień pracy, teraz działa jako zadanie w tle.


Przykład z Rzeczywistości: Biblioteka Umów Prawnych

Kancelaria przechowuje 15 000 umów w udostępnionym folderze. Ich polityka wymaga frazy „CONFIDENTIAL – CLIENT XYZ” oraz pieczęci kancelarii na każdej stronie. Integrując powyższe fragmenty w nocnym skrypcie PowerShell, kancelaria osiągnęła:

  • 100 % wykrywalności brakujących znaków (wcześniej 8 % prześlizgiwało się).
  • Zero godzin ręcznej pracy przy audycie.
  • Ścieżkę audytu zapisaną na wewnętrznej liście SharePoint dla przyszłych przeglądów regulacyjnych.
// 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);
}

Skrypt działa bez nadzoru i codziennie rano wysyła podsumowanie e‑mailem.


Co Jeszcze Możesz Zrobić z GroupDocs.Watermark?

Poza audytem, przykładowy projekt pokazuje, jak zastępować i usuwać znaki wodne programowo. Zrzuty ekranu poniżej demonstrują oba działania na rzeczywistym PDF‑ie:

Text replacement — the old watermark is updated with new text, font, and color

Targeted removal — only watermarks matching both text and formatting criteria are deleted

Inne scenariusze, które możesz zbudować przy użyciu tego samego API:

  • Dodawanie niewidzialnych znaków śledzących, które zawierają unikalny identyfikator do wykrywania wycieków.
  • Masowa wymiana przestarzałych logotypów w całym archiwum.
  • Generowanie certyfikatów zgodności w formacie PDF po pomyślnym audycie.
  • Integracja z Azure Functions lub AWS Lambda w celu przetwarzania serverless.

Każdy scenariusz korzysta z tego samego rdzenia API – wystarczy podmienić kryteria wyszukiwania lub typ znaku wodnego.


Wnioski

To, co kiedyś wymagało zespołu przeglądającego strony, notującego obserwacje i ryzykowania pominiętych znaków, teraz sprowadza się do kilku sekund kodu, które generują audytowalny raport PASS/FAIL. Z GroupDocs.Watermark for .NET zyskujesz:

  • Pełną widoczność każdego znaku wodnego.
  • Niezawodne wykrywanie tekstu, stylizowanego tekstu i logotypów.
  • Automatyczne raportowanie zgodności.
  • Możliwość programowego aktualizowania lub usuwania znaków wodnych.

Wypróbuj i przekształć proces kontroli znaków wodnych z uciążliwego zadania w powtarzalną usługę.


Kolejne Kroki

  • Wypróbuj darmowy trial API – zdobądź tymczasową licencję tutaj: Temp License
  • Przeczytaj pełną dokumentację zaawansowanych opcji: Docs
  • Zapoznaj się z referencją .NET API dla wszystkich klas i metod: API Reference
  • Sklonuj projekt przykładowy na GitHubie, aby zobaczyć kompletną aplikację konsolową: GitHub Samples
  • Zadaj pytania lub podziel się swoim przypadkiem użycia na forum społeczności: Forum