La forma antigua era dolorosa
Imagine a compliance officer tasked with verifying that every contract in a shared drive carries the word “CONFIDENTIAL” and the company logo on each page. The current process looks like this:
- Open a file in a viewer.
- Flip through each page looking for the phrase or image.
- Jot notes in a spreadsheet.
- Repeat for thousands of PDFs, Word files, and presentations.
A single missed watermark can trigger a costly review, and the manual effort easily exceeds 8 hours per week for a small team. Moreover, rotating text, split words, or logos saved as images often escape the human eye, leaving the organization exposed.
Hay una manera mejor
GroupDocs.Watermark for .NET removes every guesswork step. Its format‑agnostic engine can read more than 100 document types, locate text, image and even styled watermarks, and expose all relevant metadata through a clean API. The following tutorial shows how a few concise snippets replace the manual loop with an automated, repeatable workflow.
Requisitos previos
- .NET 6.0 o posterior.
- Paquete NuGet GroupDocs.Watermark (
dotnet add package GroupDocs.Watermark). - (Opcional) una licencia temporal – vea el enlace al final de este artículo.
La nueva forma: auditoría automatizada de marcas de agua
A continuación se describen cuatro operaciones principales. Cada bloque es un ejemplo autónomo que puede insertar en una aplicación de consola, un paso de CI o un servicio en segundo plano.
Paso 1 – Escanear cada marca de agua
Primero necesitamos un inventario completo. El método Search() devuelve una colección donde cada entrada contiene texto (o imagen), ubicación, rotación, número de página y tamaño de imagen sin procesar.
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}");
}
}
Punto clave: El bucle se ejecuta en menos de un segundo para un PDF típico de 50 páginas.
Paso 2 – Verificar la marca de agua de texto requerida
Las políticas de cumplimiento a menudo exigen una frase específica (p. ej., “CONFIDENTIAL”). El TextSearchCriteria con SkipUnreadableCharacters maneja automáticamente texto dividido o rotado.
using (var wk = new Watermarker(filePath))
{
var crit = new TextSearchCriteria(expectedPhrase);
crit.SkipUnreadableCharacters = true; // ignore OCR artefacts
var hits = wk.Search(crit);
bool ok = hits.Count > 0;
Console.WriteLine($" [{(ok ? "PASS" : "FAIL")}] " +
$"'{expectedPhrase}' found {hits.Count} time(s)");
return ok;
}
El método devuelve true cuando la frase aparece al menos una vez, proporcionando una señal instantánea de PASO/FALLA.
Paso 3 – Verificar el logotipo de la empresa
Los logotipos aparecen como imágenes raster, y su apariencia puede variar ligeramente debido a la compresión. ImageDctHashSearchCriteria crea un hash perceptual del logotipo de referencia y lo compara con una tolerancia configurable.
using (var wk = new Watermarker(filePath))
{
var crit = new ImageDctHashSearchCriteria(logoPath);
crit.MaxDifference = 0.9; // tolerate moderate scaling / colour shift
var matches = wk.Search(crit);
bool ok = matches.Count > 0;
Console.WriteLine($" [{(ok ? "PASS" : "FAIL")}] " +
$"logo instances: {matches.Count}");
return ok;
}
Incluso una copia de baja resolución del logotipo será reconocida.
Paso 4 – Ejecutar un informe completo de cumplimiento
Las políticas del mundo real combinan varios requisitos. El primer bloque verifica cuatro reglas de formato — presencia de texto, fuente, tamaño y estilo negrita — cada una combinando TextSearchCriteria con TextFormattingSearchCriteria mediante .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++;
The fifth rule verifies page coverage — the watermark must appear on every page. Finally, the verdict aggregates all results:
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)");
}
The report is ready to be exported as JSON, CSV or fed directly into a ticketing system.
Comparación lado a lado: antes vs. después
| Revisión manual | Auditoría automatizada | |
|---|---|---|
| Tiempo | Horas por lote | Segundos por archivo |
| Precisión | Propensa a errores humanos | API determinista |
| Escalabilidad | Limitada a unos pocos documentos | Maneja miles |
| Código requerido | Ninguno (pero laborioso) | ~30 líneas de C# |
| Salida | Sólo inspección visual | Informe estructurado PASO/FALLA |
El contraste es evidente: lo que antes ocupaba una jornada completa ahora se ejecuta como un trabajo en segundo plano.
Ejemplo del mundo real: biblioteca de contratos legales
Un despacho de abogados almacena 15 000 contratos en una carpeta compartida. Su política requiere la frase “CONFIDENTIAL – CLIENT XYZ” y el sello del despacho en cada página. Al integrar los fragmentos anteriores en un script nocturno de PowerShell, el despacho logró:
- 100 % de detección de marcas faltantes (anteriormente se escapaban un 8 %).
- Cero horas manuales dedicadas a la auditoría.
- Un rastro de auditoría guardado en una lista interna de SharePoint para futuras revisiones regulatorias.
// 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);
}
El script se ejecuta sin supervisión y envía un resumen por correo cada mañana.
¿Qué más puedes hacer con GroupDocs.Watermark?
Más allá de la auditoría, el proyecto de ejemplo muestra cómo reemplazar y eliminar marcas de agua programáticamente. Las capturas de pantalla a continuación demuestran ambas operaciones en un PDF real:
Otros escenarios que puedes construir con la misma API:
- Agregar marcas de agua invisibles de seguimiento que incrustan un ID único para rastrear fugas.
- Reemplazar masivamente logotipos obsoletos en todo un archivo.
- Generar certificados de cumplimiento listos para PDF después de una auditoría exitosa.
- Integrar con Azure Functions o AWS Lambda para procesamiento sin servidor.
Cada escenario usa la misma API central – solo cambia los criterios de búsqueda o el tipo de marca de agua.
Conclusión
Lo que antes requería que un equipo pasara páginas, tomara notas y arriesgara marcas omitidas ahora es unos segundos de código que produce un informe auditable PASO/FALLA. Con GroupDocs.Watermark for .NET obtienes:
- Visibilidad total de cada marca de agua.
- Detección fiable de texto, texto con estilo y logotipos.
- Informes automáticos de cumplimiento.
- La capacidad de actualizar o eliminar marcas de agua programáticamente.
Pruébalo y transforma tu proceso de cumplimiento de marcas de agua de un dolor de cabeza a un servicio repetible.
Próximos pasos
- Prueba la versión gratuita de la API – obtén una licencia temporal aquí: Temp License
- Lee la documentación completa para opciones avanzadas: Docs
- Explora la referencia de la API .NET para todas las clases y métodos: API Reference
- Clona el proyecto de ejemplo en GitHub para ver una aplicación de consola completa: GitHub Samples
- Haz preguntas o comparte tu caso de uso en el foro de la comunidad: Forum