Implementing .NET Watermark File Type Printing with GroupDocs.Watermark

How to Check & Validate Supported File Formats Dynamically in .NET

Picture this: You’ve just hardcoded a list of 40+ file extensions for your upload validator. Three months later, GroupDocs releases an update with new format support. Now you’re stuck manually updating your code, testing everything again, and hoping you didn’t miss anything.

Sound familiar? There’s a smarter approach.

Instead of maintaining static lists like [".pdf", ".docx", ".xlsx"...], you can query GroupDocs.Watermark directly to get its current supported formats. This means zero maintenance—when the library updates, your validation logic automatically stays current. No code changes, no deployment headaches.

What you’ll discover in this guide:

  • How to programmatically retrieve all supported file types from GroupDocs.Watermark
  • Why dynamic format checking beats hardcoded extension lists every time
  • Practical validation patterns for file uploads, user interfaces, and configuration
  • Security considerations when validating user-submitted files
  • Common pitfalls and how to avoid them

Let’s start with the essentials you’ll need.

Prerequisites: What You’ll Need

Here’s your quick setup checklist:

  • GroupDocs.Watermark for .NET (version 20.0 or later—this is when GetSupportedFileTypes() was introduced)
  • .NET Framework 4.6.1+ or .NET Core 2.0+ / .NET 5/6/7/8 (any modern .NET runtime works)
  • Basic C# knowledge (if you understand collections and loops, you’re golden)
  • Your favorite .NET IDE (Visual Studio, VS Code, or JetBrains Rider)

Don’t worry if you’re new to GroupDocs—this tutorial assumes you’re starting from scratch.

Installing GroupDocs.Watermark in Your Project

First, let’s get the library into your project. Pick whichever method fits your workflow:

Option 1: .NET CLI (fast for terminal fans)

dotnet add package GroupDocs.Watermark

Option 2: Package Manager Console (Visual Studio users)

Install-Package GroupDocs.Watermark

Option 3: NuGet Package Manager UI

  1. Right-click your project → Manage NuGet Packages
  2. Search for “GroupDocs.Watermark”
  3. Click Install on the latest stable version

About Licensing (Yes, It Matters)

GroupDocs.Watermark isn’t open source, but you’ve got flexible options:

  • Free Trial: Full features with evaluation watermarks—perfect for testing
  • Temporary License: 30-day full-featured license for development (no watermarks)
  • Commercial License: For production deployments

For this tutorial, the free trial works perfectly. Just include the required namespace:

using System;
using GroupDocs.Watermark.Common;

class Program
{
    static void Main(string[] args)
    {
        // Your format checking code goes here
    }
}

Why Dynamic Format Checking Beats Hardcoding

Before we dive into the code, let’s talk about why this matters. You might be thinking, “Can’t I just maintain a list of extensions?” Sure, you could. But here’s what happens in the real world:

The Hardcoding Problem:

// Looks fine today...
private static readonly string[] SUPPORTED_FORMATS = { 
    ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx" 
};

// But in 6 months:
// - GroupDocs added .odt support (you missed it)
// - Your list is outdated
// - Users complain "why can't I upload ODT files?"
// - You're manually updating and redeploying

The Dynamic Approach:

// Always current, zero maintenance
var supportedFormats = FileType.GetSupportedFileTypes()
    .Select(ft => ft.Extension)
    .ToHashSet();

Benefits you get immediately:

  • Automatic updates: Library adds formats? Your validator already knows
  • Zero maintenance: No manual list updates when upgrading GroupDocs
  • Single source of truth: The library itself tells you what it supports
  • Fewer bugs: Can’t have a mismatch between your list and actual capabilities

Now let’s see this in action.

Getting All Supported Formats: The Core Implementation

Here’s where things get practical. GroupDocs.Watermark maintains an internal registry of every format it can process. You access this with a single static method call—no configuration, no complex setup.

How the Format Registry Works

Think of FileType.GetSupportedFileTypes() as asking the library “Hey, what can you actually handle?” It returns a collection of FileType objects, each representing a format GroupDocs knows how to process.

The 3-Line Implementation

Here’s the complete working code:

Step 1: Retrieve the format list

IEnumerable<FileType> supportedFileTypes = FileType.GetSupportedFileTypes();

Step 2: Display or use the formats

foreach (FileType fileType in supportedFileTypes)
{
    Console.WriteLine(fileType);
}

What’s actually happening:

  • FileType.GetSupportedFileTypes() returns all formats as FileType objects
  • It’s a static method—no need to create instances or initialize anything
  • Each FileType contains metadata: extension, description, MIME type, etc.
  • The method is lightweight—typically returns 40+ formats instantly

Complete working example:

using System;
using GroupDocs.Watermark.Common;

class Program
{
    static void Main(string[] args)
    {
        // Get all supported file types from GroupDocs.Watermark
        IEnumerable<FileType> supportedFileTypes = FileType.GetSupportedFileTypes();
        
        Console.WriteLine("GroupDocs.Watermark currently supports:\n");
        
        // Display each format
        foreach (FileType fileType in supportedFileTypes)
        {
            Console.WriteLine(fileType);
        }
        
        Console.WriteLine($"\nTotal formats supported: {supportedFileTypes.Count()}");
    }
}

Expected Output

When you run this, you’ll see something like:

GroupDocs.Watermark currently supports:

PDF (.pdf)
Microsoft Word Document (.doc)
Microsoft Word Open XML Document (.docx)
Microsoft Excel Spreadsheet (.xls)
Microsoft Excel Open XML Spreadsheet (.xlsx)
Microsoft PowerPoint Presentation (.ppt)
... (and many more)

Total formats supported: 40+

The exact number varies by version—newer releases typically add format support.

Real-World Use Cases: When You Actually Need This

Okay, you can retrieve format lists. But when would you actually use this in production code? Here are the scenarios where this feature shines:

1. Smart File Upload Validation

Stop hardcoding allowed extensions. Pull them dynamically:

public bool IsFormatSupported(string fileName)
{
    var supportedExtensions = FileType.GetSupportedFileTypes()
        .Select(ft => ft.Extension.ToLower())
        .ToHashSet();
    
    string fileExtension = Path.GetExtension(fileName).ToLower();
    return supportedExtensions.Contains(fileExtension);
}

Why this matters: When you upgrade GroupDocs and it adds new format support (say, .odt or .epub), your validator automatically allows them. No code changes needed.

Real-world scenario: You’re building a document management system. Instead of users hitting “format not supported” errors after you update the library, they can immediately use new formats. That’s better UX with less support overhead.

2. User-Facing Format Lists

Show users exactly what they can upload before they try:

public string GetSupportedFormatsMessage()
{
    var formats = FileType.GetSupportedFileTypes()
        .Select(ft => ft.Extension.ToUpper())
        .OrderBy(ext => ext);
    
    return $"Supported formats: {string.Join(", ", formats)}";
}

Output: “Supported formats: DOC, DOCX, PDF, PPT, PPTX, XLS, XLSX, …”

Pro tip: For better UX, group by category (Documents, Spreadsheets, Presentations, Images) rather than showing a flat list of 40+ extensions.

3. Configuration Validation

Some organizations restrict which formats their apps can process (compliance, storage costs, security policies). You can validate your configuration against what GroupDocs actually supports:

public bool ValidateAllowedFormats(List<string> configuredFormats)
{
    var supportedExtensions = FileType.GetSupportedFileTypes()
        .Select(ft => ft.Extension.ToLower())
        .ToHashSet();
    
    // Check if all configured formats are actually supported
    return configuredFormats.All(cf => supportedExtensions.Contains(cf.ToLower()));
}

Use case: Your appsettings.json lists allowed formats:

{
  "AllowedFormats": [".pdf", ".docx", ".xlsx"]
}

On startup, validate that these are actually supported by your GroupDocs version. If someone typos .docx as .doxc, you’ll catch it immediately.

4. Diagnostic Logging

Track which formats your application actually processes:

public void LogSupportedFormats(ILogger logger)
{
    var formats = FileType.GetSupportedFileTypes();
    logger.LogInformation($"Initialized with support for {formats.Count()} file formats");
    
    if (logger.IsEnabled(LogLevel.Debug))
    {
        foreach (var format in formats)
        {
            logger.LogDebug($"Supports: {format}");
        }
    }
}

Why log this? When troubleshooting format-related issues, it’s helpful to know exactly which formats your deployed version supports. Library version mismatches between environments? Your logs will tell you.

5. Dynamic UI Generation

Build upload interfaces that automatically adapt to supported formats:

// Generate an HTML accept attribute dynamically
public string GenerateFileInputAccept()
{
    var extensions = FileType.GetSupportedFileTypes()
        .Select(ft => ft.Extension.ToLower());
    
    return string.Join(",", extensions);
}

// Usage in ASP.NET Razor:
// <input type="file" accept="@Model.GenerateFileInputAccept()" />

The browser’s file picker will now only show supported formats—no need to manually maintain the list.

Security Considerations for File Validation

Here’s something often overlooked: file extension checking is NOT sufficient security. Just because a file has a .pdf extension doesn’t mean it’s actually a PDF (or even safe).

The Extension Spoofing Problem

An attacker can easily rename malicious.exe to malicious.pdf. Your extension check will pass, but you’re now processing potentially dangerous content.

Defense-in-Depth Approach

Layer 1: Extension Validation (what we’ve covered)

bool extensionValid = IsFormatSupported(fileName);

Layer 2: MIME Type Validation (for web uploads)

// In ASP.NET Core
bool mimeTypeValid = Request.Form.Files[0].ContentType 
    .StartsWith("application/") || 
    Request.Form.Files[0].ContentType.StartsWith("image/");

Layer 3: Content Validation (the real check)

// Try to actually open the file with GroupDocs
try 
{
    using (Watermarker watermarker = new Watermarker(filePath))
    {
        // If we get here, the file format is truly valid
        // GroupDocs successfully parsed it
    }
}
catch (UnsupportedFileTypeException)
{
    // File claimed to be supported format but isn't
    // Reject it
}

Best practice: Use GetSupportedFileTypes() for UI/UX (showing allowed formats, early rejection). But always attempt to actually process the file as your final validation step. If GroupDocs can’t open it, it’s not a valid format regardless of extension.

Additional Security Tips

  • Scan uploaded files with antivirus before processing
  • Limit file sizes (huge files can be DoS attacks)
  • Process files in isolated environments (containers, sandboxes)
  • Never trust client-side validation alone—always validate server-side
  • Log all file processing attempts for audit trails

Performance Optimization: Caching Format Lists

While GetSupportedFileTypes() is lightweight, there’s no reason to call it repeatedly. Let’s optimize for production scenarios.

The Problem with Repeated Calls

// BAD: Calling this in a tight loop
for (int i = 0; i < 10000; i++)
{
    var formats = FileType.GetSupportedFileTypes(); // Wasteful!
    bool isSupported = formats.Any(f => f.Extension == userExtension);
}

Each call rebuilds the format list from scratch. Not terrible performance-wise, but unnecessary.

Solution 1: Lazy Initialization (Thread-Safe)

public class FormatValidator
{
    private static readonly Lazy<HashSet<string>> _supportedExtensions = 
        new Lazy<HashSet<string>>(() => 
            FileType.GetSupportedFileTypes()
                .Select(ft => ft.Extension.ToLower())
                .ToHashSet()
        );
    
    public static bool IsSupported(string fileName)
    {
        string ext = Path.GetExtension(fileName).ToLower();
        return _supportedExtensions.Value.Contains(ext);
    }
}

Why this works:

  • Lazy<T> ensures initialization happens only once
  • Thread-safe by default
  • HashSet gives O(1) lookup instead of O(n) with IEnumerable.Any()

Solution 2: Dependency Injection (ASP.NET Core)

For web applications, register as a singleton:

public interface IFormatService
{
    IEnumerable<FileType> GetSupportedFormats();
    bool IsFormatSupported(string fileName);
}

public class FormatService : IFormatService
{
    private readonly HashSet<string> _supportedExtensions;
    private readonly IEnumerable<FileType> _supportedFormats;
    
    public FormatService()
    {
        _supportedFormats = FileType.GetSupportedFileTypes().ToList();
        _supportedExtensions = _supportedFormats
            .Select(ft => ft.Extension.ToLower())
            .ToHashSet();
    }
    
    public IEnumerable<FileType> GetSupportedFormats() => _supportedFormats;
    
    public bool IsFormatSupported(string fileName)
    {
        string ext = Path.GetExtension(fileName)?.ToLower() ?? string.Empty;
        return _supportedExtensions.Contains(ext);
    }
}

Register in Startup.cs or Program.cs:

services.AddSingleton<IFormatService, FormatService>();

Now inject it wherever needed:

public class DocumentController : ControllerBase
{
    private readonly IFormatService _formatService;
    
    public DocumentController(IFormatService formatService)
    {
        _formatService = formatService;
    }
    
    [HttpPost("upload")]
    public IActionResult Upload(IFormFile file)
    {
        if (!_formatService.IsFormatSupported(file.FileName))
        {
            return BadRequest("Unsupported file format");
        }
        
        // Process file...
    }
}

Memory Considerations

The format list is small (typically < 10KB in memory), so caching it is always worth it. However:

  • Do cache if checking formats frequently (thousands of times per second)
  • Do cache in web applications (one instance per app lifetime)
  • Don’t worry about memory unless you’re in an extremely constrained environment

Common Mistakes to Avoid

Let’s cover the pitfalls I’ve seen developers run into:

Mistake 1: Not Handling Null/Empty Filenames

// BAD: Can throw NullReferenceException
public bool IsSupported(string fileName)
{
    string ext = Path.GetExtension(fileName).ToLower();
    return _supportedExtensions.Contains(ext);
}

// GOOD: Defensive programming
public bool IsSupported(string fileName)
{
    if (string.IsNullOrWhiteSpace(fileName))
        return false;
    
    string ext = Path.GetExtension(fileName)?.ToLower() ?? string.Empty;
    return _supportedExtensions.Contains(ext);
}

Mistake 2: Case-Sensitive Comparisons

// BAD: Misses .PDF, .Pdf, .PdF, etc.
supportedExtensions.Contains(userExtension)

// GOOD: Case-insensitive
supportedExtensions.Contains(userExtension.ToLower())
// Or use StringComparer.OrdinalIgnoreCase in HashSet constructor

Mistake 3: Forgetting the Leading Dot

// Users might input "pdf" or ".pdf"
// Normalize consistently:
string normalizedExt = userInput.StartsWith(".") 
    ? userInput.ToLower() 
    : "." + userInput.ToLower();

Mistake 4: Only Checking Extensions (Security Risk)

As covered earlier, extension validation is just the first layer. Always attempt to actually process the file:

// Extension check is necessary but not sufficient
if (!IsFormatSupported(fileName))
{
    return "Extension not supported";
}

// The real validation: can GroupDocs actually open it?
try 
{
    using (var watermarker = new Watermarker(filePath))
    {
        // Success - it's a valid file
    }
}
catch (UnsupportedFileTypeException)
{
    return "File is corrupted or not a valid format";
}

Mistake 5: Checking Formats Too Late

Validate before uploading large files to save bandwidth and server resources:

// Client-side: Check extension before upload
function validateFile(file) {
    const allowedExtensions = @Html.Raw(Json.Serialize(Model.AllowedExtensions));
    const fileExt = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
    
    if (!allowedExtensions.includes(fileExt)) {
        alert('Unsupported file format');
        return false;
    }
    
    return true; // Proceed with upload
}

Important: This is just a UX improvement. Always validate server-side too—client-side checks can be bypassed.

Troubleshooting Guide

“FileType doesn’t contain a definition for GetSupportedFileTypes”

Symptoms: Compiler error, method not found

Cause: You’re using GroupDocs.Watermark version < 20.0

Solution: Update to the latest version:

dotnet add package GroupDocs.Watermark --version 24.0.0

Or check your current version:

dotnet list package

Empty List or No Formats Returned

Symptoms: GetSupportedFileTypes() returns empty collection

Possible causes:

  1. Licensing issue: Evaluation mode might be restricted
  2. Assembly loading problem: GroupDocs libraries not properly loaded
  3. Version mismatch: Mixing incompatible GroupDocs assemblies

Debugging steps:

try
{
    var formats = FileType.GetSupportedFileTypes();
    Console.WriteLine($"Found {formats.Count()} formats");
    
    if (!formats.Any())
    {
        Console.WriteLine("No formats found - possible licensing or assembly issue");
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
    Console.WriteLine($"Stack trace: {ex.StackTrace}");
}

Console Window Closes Immediately

Symptoms: You run the program, see a flash, then nothing

Cause: Console applications exit as soon as Main() completes

Solution: Add a pause:

static void Main(string[] args)
{
    // Your code here
    
    Console.WriteLine("\nPress any key to exit...");
    Console.ReadKey();
}

Or run from terminal:

dotnet run

“Could not load file or assembly” Errors

Symptoms: Runtime exception about missing assemblies

Causes:

  • .NET framework version mismatch
  • Missing dependencies
  • NuGet restore failed

Solutions:

# Clean and rebuild
dotnet clean
dotnet restore
dotnet build

# Check target framework matches requirements
# In .csproj:
<TargetFramework>net6.0</TargetFramework>
<!-- or -->
<TargetFramework>net48</TargetFramework>

Format Supported But File Won’t Process

Symptoms: IsFormatSupported() returns true, but Watermarker throws exception

Explanation: File extension matches, but file content is corrupted or invalid

This is expected behavior: Extension checking is just a preliminary filter. The file might:

  • Be corrupted
  • Have wrong extension (renamed)
  • Be password-protected
  • Use unsupported variant of the format

Solution: Wrap processing in try-catch and handle gracefully:

if (IsFormatSupported(fileName))
{
    try
    {
        using (var watermarker = new Watermarker(filePath))
        {
            // Process...
        }
    }
    catch (UnsupportedFileTypeException)
    {
        // Handle: File claimed to be supported but isn't valid
    }
    catch (PasswordRequiredException)
    {
        // Handle: File is password-protected
    }
}

Best Practices Checklist

Before you deploy format validation to production, run through this checklist:

Architecture:

  • Format list cached (not called repeatedly)
  • Using dependency injection in web apps
  • Thread-safe implementation if multi-threaded

Security:

  • Extension validation is first layer, not only layer
  • Actually attempting to process files as final validation
  • Logging all format validation attempts
  • File size limits enforced
  • Uploaded files scanned for malware

User Experience:

  • Showing supported formats before upload
  • Clear error messages when format not supported
  • Client-side validation for immediate feedback (+ server-side)

Error Handling:

  • Null/empty filename checks
  • Case-insensitive extension comparisons
  • Try-catch around file processing
  • Graceful degradation when formats change

Testing:

  • Unit tests for format validation logic
  • Integration tests with actual files
  • Edge cases tested (empty extensions, no extensions, etc.)
  • Load testing if processing high volume

Wrapping Up: Your Action Plan

You now have everything you need to implement smart, dynamic file format validation in .NET. Here’s what you learned:

Core takeaway: Stop hardcoding format lists. Let GroupDocs tell you what it supports with FileType.GetSupportedFileTypes().

Key benefits you unlock:

  • Zero-maintenance format validation
  • Automatic support for new formats when upgrading
  • Better user experience with accurate format lists
  • Reduced support burden from format-related issues

Next steps to take:

  1. Replace hardcoded format lists in your existing projects with dynamic retrieval
  2. Add caching using Lazy initialization or DI for performance
  3. Implement layered security—extension check + content validation
  4. Build user-facing format lists that update automatically
  5. Set up logging to track format validation in production

Want to go deeper? Explore these related topics:

  • Adding watermarks to documents (main GroupDocs feature)
  • Building complete file processing pipelines
  • Format-specific watermark handling
  • Advanced watermark search and removal

The beauty of this approach? Your code becomes self-maintaining. No more updating format lists every time you upgrade libraries. The source of truth is the library itself—just ask it what it supports.

Ready to implement this? The code is literally three lines away. Go make your file validation smarter!

Frequently Asked Questions

How many file formats does GroupDocs.Watermark actually support in 2025?

As of version 24.x, GroupDocs.Watermark supports 40+ file formats including PDF, Microsoft Office (DOC/DOCX, XLS/XLSX, PPT/PPTX), OpenDocument formats (ODT, ODS, ODP), various image formats (PNG, JPG, TIFF, BMP, GIF, WEBP), and more. The exact count increases with each major release, which is precisely why using GetSupportedFileTypes() beats maintaining a manual list.

Can I filter the list to show only document formats or only images?

Yes! The FileType objects have properties you can filter on. While there’s no built-in category property, you can filter by extension patterns:

// Documents only
var documentFormats = FileType.GetSupportedFileTypes()
    .Where(ft => new[] { ".pdf", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ods", ".ppt", ".pptx" }
        .Contains(ft.Extension.ToLower()));

// Images only
var imageFormats = FileType.GetSupportedFileTypes()
    .Where(ft => new[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp" }
        .Contains(ft.Extension.ToLower()));

Does GetSupportedFileTypes() require an internet connection?

No—it’s completely offline. The method reads from GroupDocs.Watermark’s internal registry, which is compiled into the library. This makes it perfect for:

  • Air-gapped environments
  • Offline applications
  • Environments with restricted internet access
  • High-reliability systems where external dependencies are problematic

Will this work with .NET Framework 4.0 or older?

Unfortunately, no. GroupDocs.Watermark requires .NET Framework 4.6.1 or higher. If you’re stuck on .NET 4.0, you’ll need to either:

  • Upgrade your target framework (recommended)
  • Use an older version of GroupDocs.Watermark (not recommended—you’ll miss features and bug fixes)

For new projects, target .NET 6/8 or later for best performance and long-term support.

Can I use this for client-side validation in JavaScript/Blazor?

For Blazor WebAssembly: Yes, if you’re using Blazor WebAssembly, you can call this from C# code that runs in the browser. Just remember to cache the results since WASM has performance considerations.

For JavaScript/React/Angular: Not directly. You’ll need to create an API endpoint that returns the supported formats:

// ASP.NET Core API
[HttpGet("api/formats")]
public IActionResult GetSupportedFormats()
{
    var formats = FileType.GetSupportedFileTypes()
        .Select(ft => new { ft.Extension, ft.Description })
        .ToList();
    
    return Ok(formats);
}

Then fetch it from your JavaScript:

const response = await fetch('/api/formats');
const supportedFormats = await response.json();

How often should I call GetSupportedFileTypes()?

Ideally, once per application lifetime (or once per request in serverless environments). The supported formats don’t change during runtime—they’re determined by the GroupDocs.Watermark version you’ve deployed.

Best practices:

  • Desktop apps: Cache in a static field during startup
  • Web apps: Register as a singleton service (shown in the DI section above)
  • Serverless functions: Cache per function instance (cold start optimization)
  • Never call it in tight loops or per-file processing

The performance impact of repeated calls is minimal, but there’s simply no reason to rebuild the same list over and over.

Does checking supported formats guarantee the file will process successfully?

No—extension checking is necessary but not sufficient. Here’s why:

A file might pass your format check but still fail to process because:

  • The file is corrupted (incomplete download, storage error)
  • The extension is spoofed (malicious.exe renamed to malicious.pdf)
  • The file is password-protected (GroupDocs needs the password)
  • The file uses an unsupported variant of the format (rare edge cases)
  • The file is empty or has zero bytes

Always wrap actual processing in try-catch:

if (IsFormatSupported(fileName))  // First check: extension
{
    try
    {
        using (var watermarker = new Watermarker(filePath))  // Second check: can we open it?
        {
            // Success - valid file
        }
    }
    catch (Exception ex)
    {
        // Handle: file format issue, corruption, or security restriction
        _logger.LogWarning($"Failed to process {fileName}: {ex.Message}");
    }
}

Think of GetSupportedFileTypes() as a preliminary filter, not a complete validation solution.

What about proprietary or less common document formats?

GroupDocs.Watermark focuses on mainstream business and productivity formats. You’ll find:

Well-supported:

  • Microsoft Office (DOC, DOCX, XLS, XLSX, PPT, PPTX)
  • PDF and PDF/A variants
  • OpenDocument formats (ODT, ODS, ODP)
  • Common image formats (JPEG, PNG, TIFF, BMP, GIF, WEBP)
  • Visio diagrams (VSD, VSDX)
  • Email formats (MSG, EML)

Not typically supported:

  • AutoCAD files (DWG, DXF)
  • Adobe InDesign (INDD)
  • Publisher (PUB) in older versions
  • Rare proprietary formats

To check if a specific format is supported: Just run GetSupportedFileTypes() and search the output. Don’t rely on assumptions—let the library tell you definitively.

Can I extend the supported formats list or add custom formats?

No—GroupDocs.Watermark’s format support is built into the library. You cannot add custom parsers or extend the format list through configuration.

If you need to process unsupported formats, you have a few options:

  1. Convert first: Use another library to convert unsupported formats to supported ones (e.g., LibreOffice for rare document types, ImageMagick for exotic image formats)
  2. Request support: Contact GroupDocs support—they add format support based on customer demand
  3. Use a different library: For specialized formats, you might need format-specific libraries

Example conversion workflow:

public async Task<bool> ProcessFile(string filePath)
{
    if (IsFormatSupported(filePath))
    {
        // Process directly
        return await AddWatermark(filePath);
    }
    else
    {
        // Try converting to supported format first
        string convertedPath = await ConvertToSupportedFormat(filePath);
        return await AddWatermark(convertedPath);
    }
}

Does this work with older versions of GroupDocs.Watermark?

The GetSupportedFileTypes() method was introduced in version 20.0 (released in early 2020). If you’re using an older version:

Version < 20.0: This method doesn’t exist. You’ll need to either:

  • Upgrade to version 20.0 or later (strongly recommended)
  • Maintain a manual list of supported formats based on documentation

Version 20.0 - 23.x: The method exists and works as described, though the format count may be lower

Version 24.x+: Latest format support, including newer file types and variants

To check your version:

dotnet list package | grep GroupDocs.Watermark

Or in code:

var assembly = typeof(Watermarker).Assembly;
var version = assembly.GetName().Version;
Console.WriteLine($"GroupDocs.Watermark version: {version}");

Are there performance differences between format checking methods?

Yes, but they’re all fast enough for most use cases. Here’s the breakdown:

Method 1: Fresh call each time (~1ms)

bool isSupported = FileType.GetSupportedFileTypes()
    .Any(ft => ft.Extension.Equals(userExt, StringComparison.OrdinalIgnoreCase));
  • Pros: Simple, no state to manage
  • Cons: Rebuilds list every call, O(n) search
  • Use when: Checking formats infrequently (< 100 times per minute)

Method 2: Cached HashSet (~0.01ms)

private static readonly HashSet<string> _formats = 
    FileType.GetSupportedFileTypes()
        .Select(ft => ft.Extension.ToLower())
        .ToHashSet();

bool isSupported = _formats.Contains(userExt.ToLower());
  • Pros: O(1) lookup, minimal memory (~10KB)
  • Cons: Slightly more complex setup
  • Use when: Checking formats frequently (1000+ times per minute)

Method 3: Lazy + HashSet (best of both worlds)

private static readonly Lazy<HashSet<string>> _formats = 
    new Lazy<HashSet<string>>(() => /* ... */);
  • Pros: Thread-safe, lazy initialization, O(1) lookup
  • Cons: Most complex (but not by much)
  • Use when: Multi-threaded scenarios or when initialization timing matters

Bottom line: Unless you’re validating thousands of files per second, any method works fine. Start simple, optimize if profiling shows it’s a bottleneck.

Additional Resources & Next Steps

Official Documentation:

Downloads & Licensing:

Community & Support:

Related Guides You Might Find Helpful:

  • Adding watermarks to documents (the core functionality)
  • Removing watermarks from existing documents
  • Searching for watermarks across multiple files
  • Batch processing workflows
  • Format-specific watermark strategies (PDF vs DOCX vs images)
  • Integration with cloud storage (Azure Blob, AWS S3)

Pro tip: Bookmark the release notes page to stay updated on new format support and features. When you see a new format added, your code automatically supports it—no changes needed.