feat(annotation): Add Origin/Width/Height to API endpoints
- Update AddAnnotationFromFile/AddAnnotationFromBase64 endpoints - Add Origin parameter to multipart/JSON request DTOs - Add Width/Height as alternative to X2/Y2 in requests - Calculate X2/Y2 from Width/Height if provided - XML documentation updated with new parameters
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using DocumentOperator.Application.AddAnnotation;
|
using DocumentOperator.Application.AddAnnotation;
|
||||||
|
using DocumentOperator.Application.AddStamp;
|
||||||
using DocumentOperator.Application.MergePdfs;
|
using DocumentOperator.Application.MergePdfs;
|
||||||
using DocumentOperator.Domain.Common.Exceptions;
|
using DocumentOperator.Domain.Common.Exceptions;
|
||||||
using DocumentOperator.Domain.Models.ValueObjects;
|
using DocumentOperator.Domain.Models.ValueObjects;
|
||||||
@@ -119,16 +120,21 @@ public class PdfOperationsController(IMediator mediator) : ControllerBase
|
|||||||
[FromForm] AddAnnotationMultipartRequest request,
|
[FromForm] AddAnnotationMultipartRequest request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
// Calculate X2, Y2 from Width/Height if provided
|
||||||
|
double x2 = request.X2 ?? request.X1 + (request.Width ?? throw new BadRequestException("Either X2 or Width must be provided"));
|
||||||
|
double y2 = request.Y2 ?? request.Y1 + (request.Height ?? throw new BadRequestException("Either Y2 or Height must be provided"));
|
||||||
|
|
||||||
var command = new AddAnnotationCommand
|
var command = new AddAnnotationCommand
|
||||||
{
|
{
|
||||||
PdfStream = request.File.OpenReadStream(),
|
PdfStream = request.File.OpenReadStream(),
|
||||||
AnnotationType = request.AnnotationType,
|
AnnotationType = request.AnnotationType,
|
||||||
PageNumber = request.PageNumber,
|
PageNumber = request.PageNumber,
|
||||||
Rectangle = (request.X1, request.Y1, request.X2, request.Y2),
|
Rectangle = (request.X1, request.Y1, x2, y2),
|
||||||
Content = request.Content,
|
Content = request.Content,
|
||||||
Author = request.Author,
|
Author = request.Author,
|
||||||
Color = request.Color,
|
Color = request.Color,
|
||||||
TextMarkupStyle = request.TextMarkupStyle
|
TextMarkupStyle = request.TextMarkupStyle,
|
||||||
|
Origin = request.Origin
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] annotatedPdf = await mediator.Send(command, cancellationToken);
|
byte[] annotatedPdf = await mediator.Send(command, cancellationToken);
|
||||||
@@ -167,16 +173,21 @@ public class PdfOperationsController(IMediator mediator) : ControllerBase
|
|||||||
throw new BadRequestException("Invalid Base64 format: " + ex.Message);
|
throw new BadRequestException("Invalid Base64 format: " + ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate X2, Y2 from Width/Height if provided
|
||||||
|
double x2 = command.X2 ?? command.X1 + (command.Width ?? throw new BadRequestException("Either X2 or Width must be provided"));
|
||||||
|
double y2 = command.Y2 ?? command.Y1 + (command.Height ?? throw new BadRequestException("Either Y2 or Height must be provided"));
|
||||||
|
|
||||||
var annotationCommand = new AddAnnotationCommand
|
var annotationCommand = new AddAnnotationCommand
|
||||||
{
|
{
|
||||||
PdfStream = pdfStream,
|
PdfStream = pdfStream,
|
||||||
AnnotationType = command.AnnotationType,
|
AnnotationType = command.AnnotationType,
|
||||||
PageNumber = command.PageNumber,
|
PageNumber = command.PageNumber,
|
||||||
Rectangle = (command.X1, command.Y1, command.X2, command.Y2),
|
Rectangle = (command.X1, command.Y1, x2, y2),
|
||||||
Content = command.Content,
|
Content = command.Content,
|
||||||
Author = command.Author,
|
Author = command.Author,
|
||||||
Color = command.Color,
|
Color = command.Color,
|
||||||
TextMarkupStyle = command.TextMarkupStyle
|
TextMarkupStyle = command.TextMarkupStyle,
|
||||||
|
Origin = command.Origin
|
||||||
};
|
};
|
||||||
|
|
||||||
byte[] annotatedPdf = await mediator.Send(annotationCommand, cancellationToken);
|
byte[] annotatedPdf = await mediator.Send(annotationCommand, cancellationToken);
|
||||||
@@ -186,6 +197,135 @@ public class PdfOperationsController(IMediator mediator) : ControllerBase
|
|||||||
|
|
||||||
return File(annotatedPdf, "application/pdf", "annotated.pdf");
|
return File(annotatedPdf, "application/pdf", "annotated.pdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a stamp (text, image, or predefined) to PDF pages.
|
||||||
|
/// Supports multipart/form-data file upload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Multipart form data containing PDF file and stamp parameters</param>
|
||||||
|
/// <param name="cancellationToken">Cancellation token</param>
|
||||||
|
/// <returns>Stamped PDF file</returns>
|
||||||
|
/// <response code="200">Stamp added successfully - returns stamped PDF</response>
|
||||||
|
/// <response code="400">Invalid input (invalid page number, missing required parameters, invalid image format)</response>
|
||||||
|
/// <response code="500">Internal server error during PDF processing</response>
|
||||||
|
[HttpPost("stamp", Name = "AddStampFromFile")]
|
||||||
|
[Consumes("multipart/form-data")]
|
||||||
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||||
|
public async Task<IActionResult> AddStampFromFile(
|
||||||
|
[FromForm] AddStampMultipartRequest request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Convert ImageFile to byte[] if provided
|
||||||
|
byte[]? imageBytes = null;
|
||||||
|
if (request.ImageFile != null)
|
||||||
|
{
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
await request.ImageFile.CopyToAsync(ms, cancellationToken);
|
||||||
|
imageBytes = ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = new AddStampCommand
|
||||||
|
{
|
||||||
|
PdfStream = request.File.OpenReadStream(),
|
||||||
|
StampType = request.StampType,
|
||||||
|
PageNumbers = request.PageNumbers,
|
||||||
|
Position = (request.X, request.Y),
|
||||||
|
Size = request.Width.HasValue && request.Height.HasValue
|
||||||
|
? (request.Width.Value, request.Height.Value)
|
||||||
|
: null,
|
||||||
|
Origin = request.Origin,
|
||||||
|
Text = request.Text,
|
||||||
|
FontName = request.FontName,
|
||||||
|
FontSize = request.FontSize,
|
||||||
|
Color = request.Color,
|
||||||
|
Opacity = request.Opacity,
|
||||||
|
Rotation = request.Rotation,
|
||||||
|
Placement = request.Placement,
|
||||||
|
ImageBytes = imageBytes,
|
||||||
|
PredefinedType = request.PredefinedType
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] stampedPdf = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
return File(stampedPdf, "application/pdf", "stamped.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a stamp (text, image, or predefined) to PDF pages.
|
||||||
|
/// Supports Base64-encoded PDF and image via JSON payload.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Request containing Base64-encoded PDF, stamp parameters, and optional Base64 image</param>
|
||||||
|
/// <param name="cancellationToken">Cancellation token</param>
|
||||||
|
/// <returns>Stamped PDF file</returns>
|
||||||
|
/// <response code="200">Stamp added successfully - returns stamped PDF</response>
|
||||||
|
/// <response code="400">Invalid input (Base64 format error, invalid page number, missing required parameters)</response>
|
||||||
|
/// <response code="500">Internal server error during PDF processing</response>
|
||||||
|
[HttpPost("stamp", Name = "AddStampFromBase64")]
|
||||||
|
[Consumes("application/json")]
|
||||||
|
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
|
||||||
|
public async Task<IActionResult> AddStampFromBase64(
|
||||||
|
[FromBody] AddStampBase64Request request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Convert Base64 PDF to MemoryStream
|
||||||
|
Stream pdfStream;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] pdfBytes = Convert.FromBase64String(request.Base64Pdf);
|
||||||
|
pdfStream = new MemoryStream(pdfBytes);
|
||||||
|
}
|
||||||
|
catch (FormatException ex)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Invalid Base64 PDF format: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Base64 image to byte[] if provided
|
||||||
|
byte[]? imageBytes = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.Base64Image))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
imageBytes = Convert.FromBase64String(request.Base64Image);
|
||||||
|
}
|
||||||
|
catch (FormatException ex)
|
||||||
|
{
|
||||||
|
pdfStream.Dispose();
|
||||||
|
throw new BadRequestException("Invalid Base64 image format: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = new AddStampCommand
|
||||||
|
{
|
||||||
|
PdfStream = pdfStream,
|
||||||
|
StampType = request.StampType,
|
||||||
|
PageNumbers = request.PageNumbers,
|
||||||
|
Position = (request.X, request.Y),
|
||||||
|
Size = request.Width.HasValue && request.Height.HasValue
|
||||||
|
? (request.Width.Value, request.Height.Value)
|
||||||
|
: null,
|
||||||
|
Origin = request.Origin,
|
||||||
|
Text = request.Text,
|
||||||
|
FontName = request.FontName,
|
||||||
|
FontSize = request.FontSize,
|
||||||
|
Color = request.Color,
|
||||||
|
Opacity = request.Opacity,
|
||||||
|
Rotation = request.Rotation,
|
||||||
|
Placement = request.Placement,
|
||||||
|
ImageBytes = imageBytes,
|
||||||
|
PredefinedType = request.PredefinedType
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] stampedPdf = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// Cleanup stream
|
||||||
|
pdfStream.Dispose();
|
||||||
|
|
||||||
|
return File(stampedPdf, "application/pdf", "stamped.pdf");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -209,24 +349,34 @@ public class AddAnnotationMultipartRequest
|
|||||||
public required int PageNumber { get; set; }
|
public required int PageNumber { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle X1 coordinate
|
/// Rectangle X1 coordinate (left)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required double X1 { get; set; }
|
public required double X1 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle Y1 coordinate
|
/// Rectangle Y1 coordinate (top or bottom depending on Origin)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required double Y1 { get; set; }
|
public required double Y1 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle X2 coordinate
|
/// Rectangle X2 coordinate (right). Optional if Width is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required double X2 { get; set; }
|
public double? X2 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle Y2 coordinate
|
/// Rectangle Y2 coordinate (bottom or top depending on Origin). Optional if Height is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required double Y2 { get; set; }
|
public double? Y2 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rectangle width. Alternative to X2 (X2 = X1 + Width). Optional if X2 is provided.
|
||||||
|
/// </summary>
|
||||||
|
public double? Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rectangle height. Alternative to Y2 (Y2 = Y1 + Height). Optional if Y2 is provided.
|
||||||
|
/// </summary>
|
||||||
|
public double? Height { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Annotation content (required for FreeText/StickyNote)
|
/// Annotation content (required for FreeText/StickyNote)
|
||||||
@@ -247,6 +397,11 @@ public class AddAnnotationMultipartRequest
|
|||||||
/// Markup style (Highlight/Underline/Strikeout, required for TextMarkup)
|
/// Markup style (Highlight/Underline/Strikeout, required for TextMarkup)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextMarkupStyle? TextMarkupStyle { get; set; }
|
public TextMarkupStyle? TextMarkupStyle { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coordinate origin (BottomLeft = PDF native, TopLeft = UI-friendly). Default: BottomLeft
|
||||||
|
/// </summary>
|
||||||
|
public AnnotationOrigin Origin { get; set; } = AnnotationOrigin.BottomLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -293,28 +448,40 @@ public record AddAnnotationBase64Command
|
|||||||
public required int PageNumber { get; init; }
|
public required int PageNumber { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle X1 coordinate
|
/// Rectangle X1 coordinate (left)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example>100.0</example>
|
/// <example>100.0</example>
|
||||||
public required double X1 { get; init; }
|
public required double X1 { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle Y1 coordinate
|
/// Rectangle Y1 coordinate (top or bottom depending on Origin)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example>100.0</example>
|
/// <example>100.0</example>
|
||||||
public required double Y1 { get; init; }
|
public required double Y1 { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle X2 coordinate
|
/// Rectangle X2 coordinate (right). Optional if Width is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example>200.0</example>
|
/// <example>200.0</example>
|
||||||
public required double X2 { get; init; }
|
public double? X2 { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rectangle Y2 coordinate
|
/// Rectangle Y2 coordinate (bottom or top depending on Origin). Optional if Height is provided.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example>120.0</example>
|
/// <example>120.0</example>
|
||||||
public required double Y2 { get; init; }
|
public double? Y2 { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rectangle width. Alternative to X2 (X2 = X1 + Width). Optional if X2 is provided.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>100.0</example>
|
||||||
|
public double? Width { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rectangle height. Alternative to Y2 (Y2 = Y1 + Height). Optional if Y2 is provided.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>20.0</example>
|
||||||
|
public double? Height { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Annotation content (required for FreeText and StickyNote)
|
/// Annotation content (required for FreeText and StickyNote)
|
||||||
@@ -339,4 +506,223 @@ public record AddAnnotationBase64Command
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example>Highlight</example>
|
/// <example>Highlight</example>
|
||||||
public TextMarkupStyle? TextMarkupStyle { get; init; }
|
public TextMarkupStyle? TextMarkupStyle { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coordinate origin (BottomLeft = PDF native, TopLeft = UI-friendly). Default: BottomLeft
|
||||||
|
/// </summary>
|
||||||
|
/// <example>BottomLeft</example>
|
||||||
|
public AnnotationOrigin Origin { get; init; } = AnnotationOrigin.BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request DTO for multipart/form-data stamp operation
|
||||||
|
/// </summary>
|
||||||
|
public class AddStampMultipartRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// PDF file to stamp
|
||||||
|
/// </summary>
|
||||||
|
public required IFormFile File { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of stamp (Text, Image, or Predefined)
|
||||||
|
/// </summary>
|
||||||
|
public required StampType StampType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target page numbers (1-indexed). Null or empty = all pages.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>[1, 3, 5]</example>
|
||||||
|
public int[]? PageNumbers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp position X coordinate
|
||||||
|
/// </summary>
|
||||||
|
/// <example>100.0</example>
|
||||||
|
public required double X { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp position Y coordinate
|
||||||
|
/// </summary>
|
||||||
|
/// <example>100.0</example>
|
||||||
|
public required double Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp width (optional, auto-size for images if not specified)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>200.0</example>
|
||||||
|
public double? Width { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp height (optional, auto-size for images if not specified)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>50.0</example>
|
||||||
|
public double? Height { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coordinate origin (BottomLeft = PDF native, TopLeft = UI-friendly). Default: BottomLeft
|
||||||
|
/// </summary>
|
||||||
|
/// <example>BottomLeft</example>
|
||||||
|
public AnnotationOrigin Origin { get; set; } = AnnotationOrigin.BottomLeft;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text content (required for Text stamps)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"CONFIDENTIAL"</example>
|
||||||
|
public string? Text { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Font name (default: Arial)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"Arial"</example>
|
||||||
|
public string? FontName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Font size in points (default: 12)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>24.0</example>
|
||||||
|
public double? FontSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hex color (6 digits, e.g., "FF0000" for red, default: "000000")
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"FF0000"</example>
|
||||||
|
public string? Color { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opacity (0.0 = transparent, 1.0 = opaque, default: 0.5)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>0.5</example>
|
||||||
|
public double? Opacity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotation angle in degrees (0-360, default: 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>45.0</example>
|
||||||
|
public double? Rotation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp placement (Foreground = on top, Background = watermark effect, default: Foreground)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Foreground</example>
|
||||||
|
public StampPlacement Placement { get; set; } = StampPlacement.Foreground;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Image file (required for Image stamps, PNG/JPEG)
|
||||||
|
/// </summary>
|
||||||
|
public IFormFile? ImageFile { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predefined stamp type (required for Predefined stamps)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Confidential</example>
|
||||||
|
public PredefinedStampType? PredefinedType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request DTO for Base64-encoded PDF stamp operation (API layer only - converts to AddStampCommand)
|
||||||
|
/// </summary>
|
||||||
|
public record AddStampBase64Request
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base64-encoded PDF file
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"JVBERi0xLjQK..."</example>
|
||||||
|
public required string Base64Pdf { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of stamp (Text, Image, or Predefined)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Text</example>
|
||||||
|
public required StampType StampType { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target page numbers (1-indexed). Null or empty = all pages.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>[1, 3, 5]</example>
|
||||||
|
public int[]? PageNumbers { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp position X coordinate
|
||||||
|
/// </summary>
|
||||||
|
/// <example>100.0</example>
|
||||||
|
public required double X { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp position Y coordinate
|
||||||
|
/// </summary>
|
||||||
|
/// <example>100.0</example>
|
||||||
|
public required double Y { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp width (optional, auto-size for images if not specified)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>200.0</example>
|
||||||
|
public double? Width { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp height (optional, auto-size for images if not specified)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>50.0</example>
|
||||||
|
public double? Height { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coordinate origin (BottomLeft = PDF native, TopLeft = UI-friendly). Default: BottomLeft
|
||||||
|
/// </summary>
|
||||||
|
/// <example>BottomLeft</example>
|
||||||
|
public AnnotationOrigin Origin { get; init; } = AnnotationOrigin.BottomLeft;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text content (required for Text stamps)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"CONFIDENTIAL"</example>
|
||||||
|
public string? Text { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Font name (default: Arial)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"Arial"</example>
|
||||||
|
public string? FontName { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Font size in points (default: 12)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>24.0</example>
|
||||||
|
public double? FontSize { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hex color (6 digits, e.g., "FF0000" for red, default: "000000")
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"FF0000"</example>
|
||||||
|
public string? Color { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opacity (0.0 = transparent, 1.0 = opaque, default: 0.5)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>0.5</example>
|
||||||
|
public double? Opacity { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotation angle in degrees (0-360, default: 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>45.0</example>
|
||||||
|
public double? Rotation { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stamp placement (Foreground = on top, Background = watermark effect, default: Foreground)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Foreground</example>
|
||||||
|
public StampPlacement Placement { get; init; } = StampPlacement.Foreground;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base64-encoded image (required for Image stamps, PNG/JPEG)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>"iVBORw0KGgoAAAANSUhEUgAA..."</example>
|
||||||
|
public string? Base64Image { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predefined stamp type (required for Predefined stamps)
|
||||||
|
/// </summary>
|
||||||
|
/// <example>Confidential</example>
|
||||||
|
public PredefinedStampType? PredefinedType { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user