Giriş
Kuruluşlar genellikle binlerce dosyayı – sözleşmeler, sunumlar, faturalar – tek bir işlemde markalamak veya korumak zorundadır. Bunu manuel olarak yapmak, her belgeyi açıp bir logo veya gizlilik uyarısı ekleyip tekrar kaydetmek anlamına gelir. Bu sadece zaman alıcı olmakla kalmaz, aynı zamanda insan hatasına yol açar ve yinelenen filigranlar ya da atlanan dosyalar riskini doğurur.
GroupDocs.Watermark for .NET, PDF, DOCX, PPTX, XLSX ve yaygın görüntü formatlarıyla çalışan birleşik bir API ile sorunu çözer. Örnek proje dört belge türü (DOCX, PDF, XLSX, PPTX) ile birlikte gelir; böylece her boru hattı modu gerçek dünya formatları üzerinde çalışır. Bu öğreticide, aşağıdaki adımları içeren tam bir toplu filigran boru hattı üzerinden geçeceğiz:
- Bir lisans yükler (veya değerlendirme moduna geçer).
- Bir klasörü tarar ve yalnızca kütüphanenin işleyebileceği formatları filtreler.
- Her belgeye döşeli metin filigranı uygular.
- Özel opaklık ve döndürme ile döşeli logo filigranı uygular.
- Zaten mevcut değilse filigran ekler (idempotent işleme).
- Bul ve değiştir eski şirket logosunu yeni bir logo ile değiştirir.
Bu adımların sonunda, herhangi bir .NET projesine eklenebilecek, çalıştırılmaya hazır bir çözüm elde edeceksiniz.
Toplu Filigranlamanın Önemi
- Ölçeklenebilirlik – Tek bir döngüyle onlarca ya da binlerce dosyayı işleyin.
- Tutarlılık – Aynı görsel stil her belgeye uygulanır, marka sapması ortadan kalkar.
- Güvenlik – Idempotent mantık, boru hattı yeniden çalıştırıldığında yinelenen filigranları önler.
- Geleceğe Hazırlık – Logo değiştirme kodu, her dosyayı manuel olarak dokunmadan yeniden markalaşma yapmanıza olanak tanır.
Önkoşullar
- .NET 6.0 veya üzeri.
- GroupDocs.Watermark NuGet paketi (
dotnet add package GroupDocs.Watermark). - Bir lisans dosyası (geçici veya kalıcı). Dosya eksikse örnekler değerlendirme modunda çalışır.
- Diskte iki klasör:
InputFolder– kaynak belgeleri içerir.OutputFolder– filigranlı kopyaların yazılacağı yerdir.
Adım 1 – Lisansı Yükleme
Kütüphane, değerlendirme sınırlamaları olmadan çalışmak için bir lisansa ihtiyaç duyar. Aşağıdaki kod parçacığı bir lisans dosyasını yüklemeye çalışır ve dosya bulunamazsa sessizce geri döner.
try
{
var license = new License();
license.SetLicense(LicensePath);
Console.WriteLine("License applied successfully.");
}
catch
{
Console.WriteLine("Warning: License not found. Running in evaluation mode.");
}
Temel nokta: LicensePath değişkeni .lic dosyanıza işaret etmelidir. Dosya eksikse kod devam eder; bu, hızlı testler için faydalıdır.
Adım 2 – Desteklenen Dosyaları Keşfetme
GroupDocs.Watermark yalnızca belirli uzantıları işleyebilir. Aşağıdaki yardımcı, bir klasörü tarar, FileType.GetSupportedFileTypes() ile desteklenen uzantıların bir hash kümesini oluşturur ve yalnızca eşleşen dosyaları döndürür.
if (!Directory.Exists(folderPath))
{
Console.WriteLine($"Folder not found: {folderPath}");
return new List<string>();
}
var supportedExtensions = FileType.GetSupportedFileTypes()
.Select(ft => ft.Extension.ToLowerInvariant())
.ToHashSet();
var supportedFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories)
.Where(f => supportedExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()))
.ToList();
Console.WriteLine($"Found {supportedFiles.Count} supported file(s) in '{folderPath}'.");
return supportedFiles;
Temel nokta: Bu yöntem, daha sonraki filigran döngülerinin desteklenmeyen bir formatla karşılaşmasını engeller; aksi takdirde çalışma zamanı istisnası oluşur.
Adım 3 – Döşeli Metin Filigranı Uygulama
Aşağıdaki kod kırmızı, yarı‑saydam “CONFIDENTIAL” filigranı oluşturur, ‑30° döndürür ve TileOptions kullanarak her sayfada döşer.
Directory.CreateDirectory(outputFolder);
int processed = 0, failed = 0;
foreach (var filePath in files)
{
try
{
using var watermarker = new Watermarker(filePath);
var watermark = new TextWatermark(watermarkText,
new Font("Arial", 19, FontStyle.Bold))
{
ForegroundColor = Color.Red,
Opacity = 0.3,
RotateAngle = -30,
TileOptions = new TileOptions
{
LineSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 12
},
WatermarkSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 10
}
}
};
watermarker.Add(watermark);
var outPath = Path.Combine(outputFolder, Path.GetFileName(filePath));
watermarker.Save(outPath);
processed++;
Console.WriteLine($"[OK] {Path.GetFileName(filePath)}");
}
catch (Exception ex)
{
failed++;
Console.WriteLine($"[FAIL] {Path.GetFileName(filePath)}: {ex.Message}");
}
}
Console.WriteLine($"Text watermark: {processed} processed, {failed} failed");
Temel noktalar:
TileOptionstuğla‑gibi bir desen oluşturur; bu, filigranı alt içeriği etkilemeden kaldırmayı zorlaştırır.Watermarkerformatı soyutladığı için aynı kod PDF, Word, elektronik tablo ve görüntülerde çalışır.
Adım 4 – Döşeli Logo Filigranı Uygulama
Görsel bir marka işareti tercih ediyorsanız, metin filigranını bir görüntüyle değiştirin. Aşağıdaki kod logo dosyasının varlığını kontrol eder, ardından %40 opaklık ve ‑30° döndürme ile döşer.
if (!File.Exists(logoPath))
{
Console.WriteLine($"Logo not found: {logoPath}. Skipping image mode.");
return;
}
Directory.CreateDirectory(outputFolder);
int processed = 0, failed = 0;
foreach (var filePath in files)
{
try
{
using var watermarker = new Watermarker(filePath);
using var watermark = new ImageWatermark(logoPath)
{
Opacity = 0.4,
RotateAngle = -30,
TileOptions = new TileOptions
{
LineSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 15
},
WatermarkSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 12
}
}
};
watermarker.Add(watermark);
var outPath = Path.Combine(outputFolder, Path.GetFileName(filePath));
watermarker.Save(outPath);
processed++;
Console.WriteLine($"[OK] {Path.GetFileName(filePath)} - logo applied");
}
catch (Exception ex)
{
failed++;
Console.WriteLine($"[FAIL] {Path.GetFileName(filePath)}: {ex.Message}");
}
}
Console.WriteLine($"Logo watermark: {processed} processed, {failed} failed");
Temel noktalar:
- Metin için kullanılan aynı
TileOptionsmantığı, görüntülerde de tutarlı bir görünüm sağlar. Opacityalt içeriğin okunabilir kalmasını sağlarken markanın görünür olmasını sağlar.
Adım 5 – Idempotent Filigranlama (Mevcut Filigranları Atla)
Boru hattını birden çok kez çalıştırmak, filigranların üst üste birikmesini önlemelidir. Bu kod parçacığı, yeni bir filigran eklemeden önce tam metin örneğini arar.
Directory.CreateDirectory(outputFolder);
int applied = 0, skipped = 0, failed = 0;
foreach (var filePath in files)
{
try
{
using var watermarker = new Watermarker(filePath);
var criteria = new TextSearchCriteria(watermarkText, false);
var existing = watermarker.Search(criteria);
if (existing.Count > 0)
{
skipped++;
Console.WriteLine($"[SKIP] {Path.GetFileName(filePath)} – already contains watermark");
continue;
}
var watermark = new TextWatermark(watermarkText,
new Font("Arial", 19, FontStyle.Bold))
{
ForegroundColor = Color.Red,
Opacity = 0.3,
RotateAngle = -30,
TileOptions = new TileOptions
{
LineSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 12
},
WatermarkSpacing = new MeasureValue
{
MeasureType = TileMeasureType.Percent,
Value = 10
}
}
};
watermarker.Add(watermark);
var outPath = Path.Combine(outputFolder, Path.GetFileName(filePath));
watermarker.Save(outPath);
applied++;
Console.WriteLine($"[OK] {Path.GetFileName(filePath)} – watermark applied");
}
catch (Exception ex)
{
failed++;
Console.WriteLine($"[FAIL] {Path.GetFileName(filePath)}: {ex.Message}");
}
}
Console.WriteLine($"Smart batch: {applied} applied, {skipped} skipped, {failed} failed");
Temel nokta: TextSearchCriteria içinde false (büyük/küçük harf duyarsız) kullanmak, yalnızca eklemeyi planladığınız tam filigranı içeren belgeleri atlamamızı sağlar.
Adım 6 – Klasördeki Eski Logoyu Değiştirme
Şirket yeniden markalaşırken, eski logoyu her yerde yeni logo ile değiştirmeniz gerekebilir. Aşağıdaki kod, DCT‑hash (kesinlik) ve renk‑histogram (tolerans) olmak üzere iki görüntü‑arama stratejisini birleştirir ve her eşleşmenin görüntü verisini üzerine yazar.
if (!File.Exists(oldLogoPath) || !File.Exists(newLogoPath))
{
Console.WriteLine("Old or new logo file missing – aborting replacement.");
return;
}
Directory.CreateDirectory(outputFolder);
byte[] newLogoData = File.ReadAllBytes(newLogoPath);
int replaced = 0, notFound = 0;
var settings = new WatermarkerSettings
{
SearchableObjects = new SearchableObjects
{
PdfSearchableObjects = PdfSearchableObjects.All
}
};
foreach (var filePath in files)
{
try
{
using var watermarker = new Watermarker(filePath, settings);
var dct = new ImageDctHashSearchCriteria(oldLogoPath) { MaxDifference = 0.4 };
var hist = new ImageColorHistogramSearchCriteria(oldLogoPath) { MaxDifference = 0.5 };
var criteria = dct.Or(hist);
var found = watermarker.Search(criteria);
if (found.Count == 0)
{
notFound++;
Console.WriteLine($"[--] {Path.GetFileName(filePath)} – old logo not found");
continue;
}
foreach (PossibleWatermark wm in found)
{
try
{
wm.ImageData = newLogoData;
}
catch
{
// Some watermark types cannot be overwritten – ignore.
}
}
var outPath = Path.Combine(outputFolder, Path.GetFileName(filePath));
watermarker.Save(outPath);
replaced++;
Console.WriteLine($"[OK] {Path.GetFileName(filePath)} – {found.Count} logo(s) replaced");
}
catch (Exception ex)
{
Console.WriteLine($"[FAIL] {Path.GetFileName(filePath)}: {ex.Message}");
}
}
Console.WriteLine($"Logo replacement: {replaced} updated, {notFound} without old logo");
Temel noktalar:
WatermarkerSettingsiçindePdfSearchableObjects.Allkullanmak, PDF içinde artefakt olarak depolanan logoların da aranabilmesini sağlar.- DCT‑hash ve renk‑histogram kriterlerini birleştirmek, hem vektörel (Office) hem de rasterleştirilmiş (PDF) logoları yakalar.
En İyi Uygulamalar ve İpuçları
- Çıktı klasörünü bir kez oluşturun (
Directory.CreateDirectory) – yöntem idempotenttir ve yarış koşullarını önler. - İlerlemeyi kaydedin – her adımda konsola yazılan mesajlar, hangi dosyaların başarılı ya da başarısız olduğunu hızlıca görmenizi sağlar.
OpacityveRotateAngledeğerlerini marka yönergelerinize göre ayarlayın; genellikle 0.3–0.5 arası bir değer görünür ama müdahaleci olmayan bir sonuç verir.- Idempotent akıllı toplu işi, periyodik (ör. gece) marka güncellemeleri için kullanın.
- Logo değişimini küçük bir örnek üzerinde test edin; arama kriterlerinin doğru ayarlandığından emin olun, ardından tüm depoya uygulayın.
Yaygın Sorunların Çözümü
| Belirti | Muhtemel Neden | Çözüm |
|---|---|---|
| Hiç dosya işlenmiyor | ScanFolderForSupportedFiles boş liste döndürdü |
InputFolder yolunu ve klasörde desteklenen formatların (PDF, DOCX, PPTX, XLSX, PNG, JPG vb.) bulunduğunu doğrulayın |
| Filigran görünmüyor | Opaklık çok düşük veya renk arka planla karışıyor | Opacity değerini artırın (ör. 0.5) veya ForegroundColorı kontrast bir renge değiştirin |
| PDF logoları değişim sırasında bulunamadı | Logolar içerik‑akışı çizim operatörleri olarak eklenmiş (arama yapılabilir değil) | Logoları eklerken PdfArtifactWatermarkOptions kullanarak arama yapılabilir artefaktlar olarak ekleyin |
Linux’da System.Drawing.Common istisnası |
Yerel GDI+ kütüphaneleri eksik | Hedef Linux makinesine libgdiplus kurun veya .csproj içinde Unix desteğini etkinleştirin (<RuntimeHostConfigurationOption Include="System.Drawing.EnableUnixSupport" Value="true" />). |
Sonuç
Artık tam, üretime hazır bir boru hattına sahipsiniz; bu boru hattı:
- Kütüphaneyi lisanslar.
- Desteklenen belgeleri otomatik olarak algılar.
- Döşeli metin veya logo filigranları uygular.
- Yinelenen filigranlar oluşturmadan güvenli bir şekilde birden çok kez çalışabilir.
- Tüm klasörde eski bir kurumsal logoyu yeni logo ile değiştirir.
Bu yapı taşları, .NET içinde herhangi bir marka veya belge‑koruma iş akışına uyacak şekilde birleştirilebilir.