C# SDK

Official .NET SDK for TruthMark invisible watermarking.

Installation

.NET CLI
dotnet add package TruthMark.SDK
Package Manager
Install-Package TruthMark.SDK

Quick Example

using TruthMark.SDK;

var client = new TruthMarkClient(new TruthMarkConfig
{
    ApiKey = "tm_live_your_key",
    BaseUrl = "https://truthmark-api.onrender.com"
});

// Encode
var result = await client.EncodeAsync("image.png", "Copyright 2025");
Console.WriteLine($"Download: {result.DownloadUrl}");
Console.WriteLine($"PSNR: {result.Metadata.Psnr:F1} dB");

// Decode
var decoded = await client.DecodeAsync("watermarked.png");
if (decoded.Found)
{
    Console.WriteLine($"Message: {decoded.Message}");
    Console.WriteLine($"Confidence: {decoded.Confidence * 100:F1}%");
}

API Reference

TruthMarkClient(TruthMarkConfig config)

Create a new client with configuration.

  • ApiKey (string): Your API key
  • BaseUrl (string): API base URL
  • Timeout (TimeSpan): Request timeout

EncodeAsync(string imagePath, string message)

Embed an invisible watermark. Returns Task<EncodeResult>.

DecodeAsync(string imagePath)

Extract watermark. Returns Task<DecodeResult>.

Error Handling

try
{
    var result = await client.EncodeAsync("image.png", "message");
}
catch (TruthMarkException ex)
{
    switch (ex.StatusCode)
    {
        case 401: Console.Error.WriteLine("Invalid API key"); break;
        case 429: Console.Error.WriteLine($"Rate limited. Retry after {ex.RetryAfter}s"); break;
        case 413: Console.Error.WriteLine("Image too large (max 20MB)"); break;
        default:  Console.Error.WriteLine($"Error: {ex.Message}"); break;
    }
}

Advanced Examples

ASP.NET Core Controller

[ApiController]
[Route("api/[controller]")]
public class WatermarkController : ControllerBase
{
    private readonly TruthMarkClient _client;

    public WatermarkController(TruthMarkClient client) => _client = client;

    [HttpPost("encode")]
    public async Task<IActionResult> Encode(IFormFile file, [FromForm] string message)
    {
        var tempPath = Path.GetTempFileName();
        await using (var stream = System.IO.File.Create(tempPath))
            await file.CopyToAsync(stream);

        try
        {
            var result = await _client.EncodeAsync(tempPath, message);
            return Ok(result);
        }
        finally
        {
            System.IO.File.Delete(tempPath);
        }
    }
}

Dependency Injection

// Program.cs
builder.Services.AddSingleton(new TruthMarkClient(new TruthMarkConfig
{
    ApiKey = builder.Configuration["TruthMark:ApiKey"]!,
}));

Parallel Batch Processing

var files = Directory.GetFiles("./images", "*.png");
var semaphore = new SemaphoreSlim(5);

var tasks = files.Select(async file =>
{
    await semaphore.WaitAsync();
    try
    {
        var result = await client.EncodeAsync(file, "© 2025");
        Console.WriteLine($"✓ {Path.GetFileName(file)}: PSNR={result.Metadata.Psnr:F1}dB");
        return result;
    }
    finally { semaphore.Release(); }
});

var results = await Task.WhenAll(tasks);
Console.WriteLine($"Watermarked {results.Length} images");

Best Practices

Use DI for client registration

Register TruthMarkClient as a singleton in your DI container.

Store keys in User Secrets or Key Vault

Use dotnet user-secrets for development, Azure Key Vault for production.

Don't block async code

Always use await — never .Result or .Wait().

Need Help?

Check out the API reference or reach out to support.