API cleanups

This commit is contained in:
Anthony Stirling 2025-09-17 11:05:05 +01:00
parent 5e36291e28
commit 7c1ea71810
59 changed files with 970 additions and 70 deletions

View File

@ -63,4 +63,4 @@ public interface ServerCertificateService {
return validTo;
}
}
}
}

View File

@ -72,5 +72,4 @@ public class OpenApiConfig {
.addSecurityItem(new SecurityRequirement().addList("apiKey"));
}
}
}

View File

@ -10,29 +10,42 @@ public class SpringDocConfig {
@Bean
public GroupedOpenApi pdfProcessingApi() {
return GroupedOpenApi.builder()
.group("pdf-processing")
.displayName("PDF Processing API")
.group("file-processing")
.displayName("File Processing")
.pathsToMatch("/api/v1/**")
.pathsToExclude("/api/v1/admin/**", "/api/v1/user/**", "/api/v1/settings/**", "/api/v1/ui-data/**", "/api/v1/info/**", "/api/v1/general/job/**", "/api/v1/general/files/**")
.addOpenApiCustomizer(openApi -> {
openApi.info(openApi.getInfo()
.title("Stirling PDF - Processing API")
.description("API documentation for PDF processing operations including conversion, manipulation, security, and utility functions."));
})
.pathsToExclude(
"/api/v1/admin/**",
"/api/v1/user/**",
"/api/v1/settings/**",
"/api/v1/ui-data/**",
"/api/v1/info/**",
"/api/v1/general/job/**",
"/api/v1/general/files/**")
.addOpenApiCustomizer(
openApi -> {
openApi.info(
openApi.getInfo()
.title("Stirling PDF - Processing API")
.description(
"API documentation for PDF processing operations including conversion, manipulation, security, and utility functions."));
})
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("admin")
.displayName("Admin & Management API")
.group("management")
.displayName("Management")
.pathsToMatch("/api/v1/admin/**", "/api/v1/user/**", "/api/v1/settings/**")
.addOpenApiCustomizer(openApi -> {
openApi.info(openApi.getInfo()
.title("Stirling PDF - Admin API")
.description("API documentation for administrative functions, user management, settings, and system configuration."));
})
.addOpenApiCustomizer(
openApi -> {
openApi.info(
openApi.getInfo()
.title("Stirling PDF - Admin API")
.description(
"API documentation for administrative functions, user management, settings, and system configuration."));
})
.build();
}
@ -41,12 +54,19 @@ public class SpringDocConfig {
return GroupedOpenApi.builder()
.group("system")
.displayName("System & UI API")
.pathsToMatch("/api/v1/ui-data/**", "/api/v1/info/**", "/api/v1/general/job/**", "/api/v1/general/files/**")
.addOpenApiCustomizer(openApi -> {
openApi.info(openApi.getInfo()
.title("Stirling PDF - System API")
.description("API documentation for system information, UI data, and general utility endpoints."));
})
.pathsToMatch(
"/api/v1/ui-data/**",
"/api/v1/info/**",
"/api/v1/general/job/**",
"/api/v1/general/files/**")
.addOpenApiCustomizer(
openApi -> {
openApi.info(
openApi.getInfo()
.title("Stirling PDF - System API")
.description(
"API documentation for system information, UI data, and general utility endpoints."));
})
.build();
}
}
}

View File

@ -0,0 +1,69 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* API response annotation for conversion operations that output non-PDF formats. Use for PDF to
* Word, Excel, PowerPoint, text, HTML, CSV, etc.
*
* <p>Specify the output formats this endpoint supports.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ConversionResponse {
/**
* The output formats this conversion endpoint supports. Use OutputFormat enum values to specify
* supported formats.
*/
OutputFormat[] value() default {OutputFormat.DOCX, OutputFormat.TXT, OutputFormat.RTF};
/** Supported output formats for conversion operations */
enum OutputFormat {
DOCX(
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"Microsoft Word document (DOCX)",
"binary"),
DOC("application/msword", "Microsoft Word document (DOC)", "binary"),
XLSX(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Microsoft Excel document (XLSX)",
"binary"),
PPTX(
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"Microsoft PowerPoint document (PPTX)",
"binary"),
RTF("application/rtf", "Rich Text Format document", "binary"),
TXT("text/plain", "Plain text content", "string"),
HTML("text/html", "HTML content", "string"),
CSV("text/csv", "CSV data", "string"),
XML("application/xml", "XML document", "string"),
JSON("application/json", "JSON data", "string"),
BINARY("application/octet-stream", "Binary file output", "binary");
private final String mediaType;
private final String description;
private final String schemaFormat;
OutputFormat(String mediaType, String description, String schemaFormat) {
this.mediaType = mediaType;
this.description = description;
this.schemaFormat = schemaFormat;
}
public String getMediaType() {
return mediaType;
}
public String getDescription() {
return description;
}
public String getSchemaFormat() {
return schemaFormat;
}
}
}

View File

@ -0,0 +1,30 @@
package stirling.software.SPDF.config.swagger;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "Standard error response")
public class ErrorResponse {
@Schema(description = "HTTP status code", example = "400")
private int status;
@Schema(
description = "Error message describing what went wrong",
example = "Invalid PDF file or corrupted data")
private String message;
@Schema(description = "Timestamp when the error occurred", example = "2024-01-15T10:30:00Z")
private String timestamp;
@Schema(
description = "Request path where the error occurred",
example = "/api/v1/general/rotate-pdf")
private String path;
}

View File

@ -0,0 +1,67 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for filter operations that conditionally return the original file. Use
* for operations like text filters, page count filters, size filters, etc. Returns the original PDF
* if condition is met, otherwise returns no content (204).
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "Filter condition met - returns the original PDF file",
content =
@Content(
mediaType = "application/pdf",
schema =
@Schema(
type = "string",
format = "binary",
description = "The original PDF file"))),
@ApiResponse(
responseCode = "204",
description = "Filter condition not met - no content returned",
content = @Content()),
@ApiResponse(
responseCode = "400",
description = "Bad request - Invalid filter parameters or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description =
"Unprocessable entity - PDF is valid but cannot be analyzed for filtering",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error - Unexpected error during PDF analysis",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface FilterResponse {}

View File

@ -0,0 +1,63 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for operations that return JSON data or analysis results. Use for
* analysis operations, metadata extraction, info operations, etc.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "Analysis or data extraction completed successfully",
content =
@Content(
mediaType = "application/json",
schema =
@Schema(
type = "object",
description =
"JSON object containing the requested data or analysis results"))),
@ApiResponse(
responseCode = "400",
description = "Bad request - Invalid input parameters or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description =
"Unprocessable entity - PDF is valid but cannot be analyzed or processed",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description =
"Internal server error - Unexpected error during analysis or processing",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface JsonDataResponse {}

View File

@ -0,0 +1,86 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for operations that may return multiple files or a ZIP archive. Use for
* operations like PDF to images, split PDF, or multiple file conversions.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description =
"Files processed successfully. Returns single file or ZIP archive containing multiple files.",
content = {
@Content(
mediaType = "application/pdf",
schema =
@Schema(
type = "string",
format = "binary",
description = "Single PDF file result")),
@Content(
mediaType = "application/zip",
schema =
@Schema(
type = "string",
format = "binary",
description =
"ZIP archive containing multiple output files")),
@Content(
mediaType = "image/png",
schema =
@Schema(
type = "string",
format = "binary",
description = "Single image file (PNG)")),
@Content(
mediaType = "image/jpeg",
schema =
@Schema(
type = "string",
format = "binary",
description = "Single image file (JPEG)"))
}),
@ApiResponse(
responseCode = "400",
description =
"Bad request - Invalid input parameters, unsupported file format, or corrupted files",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - Files exceed maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity - Files are valid but cannot be processed",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error - Unexpected error during file processing",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface MultiFileResponse {}

View File

@ -0,0 +1,72 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* API response annotation for PDF to Microsoft Office format conversions. Specify the exact output
* format(s) this endpoint supports.
*
* <p>Usage: @OfficeConversionResponse(OfficeFormat.DOCX) @OfficeConversionResponse({OfficeFormat.DOCX,
* OfficeFormat.DOC})
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OfficeConversionResponse {
/** The Office formats this endpoint supports. */
OfficeFormat[] value();
/** Supported Microsoft Office output formats */
enum OfficeFormat {
DOCX(
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"Microsoft Word document (DOCX)",
"Word document"),
DOC("application/msword", "Microsoft Word document (DOC)", "Word document (legacy)"),
XLSX(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Microsoft Excel document (XLSX)",
"Excel spreadsheet"),
PPTX(
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"Microsoft PowerPoint document (PPTX)",
"PowerPoint presentation"),
ODT(
"application/vnd.oasis.opendocument.text",
"OpenDocument Text document (ODT)",
"OpenDocument text"),
ODS(
"application/vnd.oasis.opendocument.spreadsheet",
"OpenDocument Spreadsheet (ODS)",
"OpenDocument spreadsheet"),
ODP(
"application/vnd.oasis.opendocument.presentation",
"OpenDocument Presentation (ODP)",
"OpenDocument presentation");
private final String mediaType;
private final String description;
private final String shortDescription;
OfficeFormat(String mediaType, String description, String shortDescription) {
this.mediaType = mediaType;
this.description = description;
this.shortDescription = shortDescription;
}
public String getMediaType() {
return mediaType;
}
public String getDescription() {
return description;
}
public String getShortDescription() {
return shortDescription;
}
}
}

View File

@ -0,0 +1,66 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for PDF to PowerPoint presentation conversions. Use for endpoints that
* convert PDF to PPTX format.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "PDF converted successfully to PowerPoint presentation",
content =
@Content(
mediaType =
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
schema =
@Schema(
type = "string",
format = "binary",
description =
"Microsoft PowerPoint presentation (PPTX)"))),
@ApiResponse(
responseCode = "400",
description =
"Bad request - Invalid input parameters, unsupported format, or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description =
"Unprocessable entity - PDF is valid but cannot be converted to PowerPoint format",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description =
"Internal server error - Unexpected error during PowerPoint conversion",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface PowerPointConversionResponse {}

View File

@ -0,0 +1,63 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* Standard API response annotation for PDF operations that take PDF input and return PDF output.
* Use for single PDF input single PDF output (SISO) operations like rotate, compress, etc.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "PDF processed successfully",
content =
@Content(
mediaType = "application/pdf",
schema =
@Schema(
type = "string",
format = "binary",
description = "The processed PDF file"))),
@ApiResponse(
responseCode = "400",
description =
"Bad request - Invalid input parameters, unsupported file format, or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description =
"Unprocessable entity - PDF is valid but cannot be processed (e.g., encrypted, corrupted)",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error - Unexpected error during PDF processing",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface StandardPdfResponse {}

View File

@ -0,0 +1,54 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* API response annotation for PDF to text/document format conversions. Specify the exact output
* format(s) this endpoint supports.
*
* <p>Usage: @TextConversionResponse(TextFormat.TXT) @TextConversionResponse({TextFormat.TXT,
* TextFormat.RTF})
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TextConversionResponse {
/** The text/document formats this endpoint supports. */
TextFormat[] value();
/** Supported text and document output formats */
enum TextFormat {
TXT("text/plain", "Plain text file", "Plain text"),
RTF("application/rtf", "Rich Text Format document", "RTF document"),
HTML("text/html", "HTML document", "HTML file"),
XML("application/xml", "XML document", "XML file"),
CSV("text/csv", "Comma-separated values file", "CSV data"),
JSON("application/json", "JSON document", "JSON data"),
MARKDOWN("text/markdown", "Markdown document", "Markdown file");
private final String mediaType;
private final String description;
private final String shortDescription;
TextFormat(String mediaType, String description, String shortDescription) {
this.mediaType = mediaType;
this.description = description;
this.shortDescription = shortDescription;
}
public String getMediaType() {
return mediaType;
}
public String getDescription() {
return description;
}
public String getShortDescription() {
return shortDescription;
}
}
}

View File

@ -0,0 +1,69 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for PDF to plain text conversions. Use for endpoints that extract text
* content from PDF.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "PDF text extracted successfully",
content = {
@Content(
mediaType = "text/plain",
schema =
@Schema(
type = "string",
description =
"Plain text content extracted from PDF")),
@Content(
mediaType = "application/rtf",
schema =
@Schema(
type = "string",
format = "binary",
description = "Rich Text Format document"))
}),
@ApiResponse(
responseCode = "400",
description = "Bad request - Invalid input parameters or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description = "Unprocessable entity - PDF is valid but text extraction failed",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error - Unexpected error during text extraction",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface TextPlainConversionResponse {}

View File

@ -0,0 +1,72 @@
package stirling.software.SPDF.config.swagger;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
/**
* API response annotation for PDF to Word document conversions. Use for endpoints that convert PDF
* to DOCX/DOC formats.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "PDF converted successfully to Word document",
content = {
@Content(
mediaType =
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
schema =
@Schema(
type = "string",
format = "binary",
description = "Microsoft Word document (DOCX)")),
@Content(
mediaType = "application/msword",
schema =
@Schema(
type = "string",
format = "binary",
description = "Microsoft Word document (DOC)"))
}),
@ApiResponse(
responseCode = "400",
description =
"Bad request - Invalid input parameters, unsupported format, or corrupted PDF",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "413",
description = "Payload too large - File exceeds maximum allowed size",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "422",
description =
"Unprocessable entity - PDF is valid but cannot be converted to Word format",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "Internal server error - Unexpected error during Word conversion",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class)))
})
public @interface WordConversionResponse {}

View File

@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.JsonDataResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -31,6 +32,7 @@ public class AnalysisController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/page-count", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get PDF page count",
description = "Returns total number of pages in PDF. Input:PDF Output:JSON Type:SISO")
@ -41,6 +43,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/basic-info", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get basic PDF information",
description = "Returns page count, version, file size. Input:PDF Output:JSON Type:SISO")
@ -55,6 +58,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/document-properties", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get PDF document properties",
description = "Returns title, author, subject, etc. Input:PDF Output:JSON Type:SISO")
@ -78,6 +82,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/page-dimensions", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get page dimensions for all pages",
description = "Returns width and height of each page. Input:PDF Output:JSON Type:SISO")
@ -98,6 +103,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/form-fields", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get form field information",
description =
@ -121,6 +127,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/annotation-info", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get annotation information",
description = "Returns count and types of annotations. Input:PDF Output:JSON Type:SISO")
@ -145,6 +152,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/font-info", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get font information",
description =
@ -167,6 +175,7 @@ public class AnalysisController {
}
@AutoJobPostMapping(value = "/security-info", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Get security information",
description =

View File

@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.BookletImpositionRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -39,12 +40,13 @@ public class BookletImpositionController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/booklet-imposition", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Create a booklet with proper page imposition",
description =
"This operation combines page reordering for booklet printing with multi-page layout. "
+ "It rearranges pages in the correct order for booklet printing and places multiple pages "
+ "on each sheet for proper folding and binding. Input:PDF Output:PDF Type:SISO")
+ "It rearranges pages in the correct order for booklet printing and places multiple pages "
+ "on each sheet for proper folding and binding. Input:PDF Output:PDF Type:SISO")
public ResponseEntity<byte[]> createBookletImposition(
@ModelAttribute BookletImpositionRequest request) throws IOException {
@ -56,7 +58,8 @@ public class BookletImpositionController {
// Validate pages per sheet for booklet
if (pagesPerSheet != 2 && pagesPerSheet != 4) {
throw new IllegalArgumentException("pagesPerSheet must be 2 or 4 for booklet imposition");
throw new IllegalArgumentException(
"pagesPerSheet must be 2 or 4 for booklet imposition");
}
PDDocument sourceDocument = pdfDocumentFactory.load(file);
@ -65,9 +68,12 @@ public class BookletImpositionController {
// Step 1: Reorder pages for booklet (reusing logic from RearrangePagesPDFController)
List<Integer> bookletOrder = getBookletPageOrder(bookletType, totalPages);
// Step 2: Create new document with multi-page layout (reusing logic from MultiPageLayoutController)
PDDocument newDocument = createBookletWithLayout(sourceDocument, bookletOrder, pagesPerSheet, addBorder, pageOrientation);
// Step 2: Create new document with multi-page layout (reusing logic from
// MultiPageLayoutController)
PDDocument newDocument =
createBookletWithLayout(
sourceDocument, bookletOrder, pagesPerSheet, addBorder, pageOrientation);
sourceDocument.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -112,75 +118,93 @@ public class BookletImpositionController {
}
// Reused and adapted logic from MultiPageLayoutController
private PDDocument createBookletWithLayout(PDDocument sourceDocument, List<Integer> pageOrder,
int pagesPerSheet, boolean addBorder, String pageOrientation) throws IOException {
PDDocument newDocument = pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
private PDDocument createBookletWithLayout(
PDDocument sourceDocument,
List<Integer> pageOrder,
int pagesPerSheet,
boolean addBorder,
String pageOrientation)
throws IOException {
PDDocument newDocument =
pdfDocumentFactory.createNewDocumentBasedOnOldDocument(sourceDocument);
int cols = pagesPerSheet == 2 ? 2 : 2; // 2x1 for 2 pages, 2x2 for 4 pages
int rows = pagesPerSheet == 2 ? 1 : 2;
int currentPageIndex = 0;
int totalOrderedPages = pageOrder.size();
while (currentPageIndex < totalOrderedPages) {
// Use landscape orientation for booklets (A4 landscape -> A5 portrait when folded)
PDRectangle pageSize = "LANDSCAPE".equals(pageOrientation) ?
new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth()) : PDRectangle.A4;
PDRectangle pageSize =
"LANDSCAPE".equals(pageOrientation)
? new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth())
: PDRectangle.A4;
PDPage newPage = new PDPage(pageSize);
newDocument.addPage(newPage);
float cellWidth = newPage.getMediaBox().getWidth() / cols;
float cellHeight = newPage.getMediaBox().getHeight() / rows;
PDPageContentStream contentStream = new PDPageContentStream(
newDocument, newPage, PDPageContentStream.AppendMode.APPEND, true, true);
PDPageContentStream contentStream =
new PDPageContentStream(
newDocument,
newPage,
PDPageContentStream.AppendMode.APPEND,
true,
true);
LayerUtility layerUtility = new LayerUtility(newDocument);
if (addBorder) {
contentStream.setLineWidth(1.5f);
contentStream.setStrokingColor(Color.BLACK);
}
// Place pages on the current sheet
for (int sheetPosition = 0; sheetPosition < pagesPerSheet && currentPageIndex < totalOrderedPages; sheetPosition++) {
for (int sheetPosition = 0;
sheetPosition < pagesPerSheet && currentPageIndex < totalOrderedPages;
sheetPosition++) {
int sourcePageIndex = pageOrder.get(currentPageIndex);
PDPage sourcePage = sourceDocument.getPage(sourcePageIndex);
PDRectangle rect = sourcePage.getMediaBox();
float scaleWidth = cellWidth / rect.getWidth();
float scaleHeight = cellHeight / rect.getHeight();
float scale = Math.min(scaleWidth, scaleHeight);
int rowIndex = sheetPosition / cols;
int colIndex = sheetPosition % cols;
float x = colIndex * cellWidth + (cellWidth - rect.getWidth() * scale) / 2;
float y = newPage.getMediaBox().getHeight()
- ((rowIndex + 1) * cellHeight - (cellHeight - rect.getHeight() * scale) / 2);
float y =
newPage.getMediaBox().getHeight()
- ((rowIndex + 1) * cellHeight
- (cellHeight - rect.getHeight() * scale) / 2);
contentStream.saveGraphicsState();
contentStream.transform(Matrix.getTranslateInstance(x, y));
contentStream.transform(Matrix.getScaleInstance(scale, scale));
PDFormXObject formXObject = layerUtility.importPageAsForm(sourceDocument, sourcePageIndex);
PDFormXObject formXObject =
layerUtility.importPageAsForm(sourceDocument, sourcePageIndex);
contentStream.drawForm(formXObject);
contentStream.restoreGraphicsState();
if (addBorder) {
float borderX = colIndex * cellWidth;
float borderY = newPage.getMediaBox().getHeight() - (rowIndex + 1) * cellHeight;
contentStream.addRect(borderX, borderY, cellWidth, cellHeight);
contentStream.stroke();
}
currentPageIndex++;
}
contentStream.close();
}
return newDocument;
}
}
}

View File

@ -20,6 +20,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.CropPdfForm;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -34,6 +35,7 @@ public class CropController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/crop", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Crops a PDF document",
description =

View File

@ -29,6 +29,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.JsonDataResponse;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.EditTableOfContentsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -45,6 +47,7 @@ public class EditTableOfContentsController {
private final ObjectMapper objectMapper;
@AutoJobPostMapping(value = "/extract-bookmarks", consumes = "multipart/form-data")
@JsonDataResponse
@Operation(
summary = "Extract PDF Bookmarks",
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
@ -153,6 +156,7 @@ public class EditTableOfContentsController {
}
@AutoJobPostMapping(value = "/edit-table-of-contents", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Edit Table of Contents",
description = "Add or edit bookmarks/table of contents in a PDF document.")

View File

@ -32,6 +32,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.MergePdfsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -155,6 +156,7 @@ public class MergeController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/merge-pdfs")
@StandardPdfResponse
@Operation(
summary = "Merge multiple PDF files into one",
description =

View File

@ -23,6 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.MergeMultiplePagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -37,6 +38,7 @@ public class MultiPageLayoutController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/multi-page-layout", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Merge multiple pages of a PDF document into a single page",
description =

View File

@ -14,6 +14,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.service.PdfImageRemovalService;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
@ -47,11 +48,12 @@ public class PdfImageRemovalController {
* @throws IOException If an error occurs while processing the PDF file.
*/
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-image-pdf")
@StandardPdfResponse
@Operation(
summary = "Remove images from file to reduce the file size.",
description =
"This endpoint remove images from file to reduce the file size.Input:PDF"
+ " Output:PDF Type:MISO")
+ " Output:PDF Type:SISO")
public ResponseEntity<byte[]> removeImages(@ModelAttribute PDFFile file) throws IOException {
// Load the PDF document
PDDocument document = pdfDocumentFactory.load(file);

View File

@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.OverlayPdfsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -40,6 +41,7 @@ public class PdfOverlayController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/overlay-pdfs", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Overlay PDF files in various modes",
description =

View File

@ -20,6 +20,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.SortTypes;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.model.api.general.RearrangePagesRequest;
@ -39,6 +40,7 @@ public class RearrangePagesPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-pages")
@StandardPdfResponse
@Operation(
summary = "Remove pages from a PDF file",
description =
@ -238,6 +240,7 @@ public class RearrangePagesPDFController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rearrange-pages")
@StandardPdfResponse
@Operation(
summary = "Rearrange pages in a PDF file",
description =

View File

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.RotatePDFRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -32,6 +33,7 @@ public class RotationController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/rotate-pdf")
@StandardPdfResponse
@Operation(
summary = "Rotate a PDF file",
description =

View File

@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.general.ScalePagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -39,6 +40,7 @@ public class ScalePagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/scale-pages", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
summary = "Change the size of a PDF page/document",
description =

View File

@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -42,6 +43,7 @@ public class SplitPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/split-pages")
@MultiFileResponse
@Operation(
summary = "Split a PDF file into separate documents",
description =

View File

@ -30,6 +30,7 @@ import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.SplitPdfByChaptersRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.PdfMetadata;
@ -118,6 +119,7 @@ public class SplitPdfByChaptersController {
}
@AutoJobPostMapping(value = "/split-pdf-by-chapters", consumes = "multipart/form-data")
@MultiFileResponse
@Operation(
summary = "Split PDFs by Chapters",
description = "Splits a PDF into chapters and returns a ZIP file.")

View File

@ -30,6 +30,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.SplitPdfBySectionsRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -44,6 +45,7 @@ public class SplitPdfBySectionsController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/split-pdf-by-sections", consumes = "multipart/form-data")
@MultiFileResponse
@Operation(
summary = "Split PDF pages into smaller sections",
description =

View File

@ -23,6 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.general.SplitPdfBySizeOrCountRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -40,6 +41,7 @@ public class SplitPdfBySizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(value = "/split-by-size-or-count", consumes = "multipart/form-data")
@MultiFileResponse
@Operation(
summary = "Auto split PDF pages into separate documents based on size or count",
description =

View File

@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.converters.EmlToPdfRequest;
@ -41,6 +42,7 @@ public class ConvertEmlToPDF {
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/eml/pdf")
@StandardPdfResponse
@Operation(
summary = "Convert EML to PDF",
description =

View File

@ -12,6 +12,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.converters.HTMLToPdfRequest;
@ -37,6 +38,7 @@ public class ConvertHtmlToPDF {
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/html/pdf")
@StandardPdfResponse
@Operation(
summary = "Convert an HTML or ZIP (containing HTML and CSS) to PDF",
description =

View File

@ -30,6 +30,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.converters.ConvertToImageRequest;
import stirling.software.SPDF.model.api.converters.ConvertToPdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
@ -52,6 +54,7 @@ public class ConvertImgPDFController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/img")
@MultiFileResponse
@Operation(
summary = "Convert PDF to image(s)",
description =
@ -212,6 +215,7 @@ public class ConvertImgPDFController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/img/pdf")
@StandardPdfResponse
@Operation(
summary = "Convert images to a PDF file",
description =

View File

@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
import stirling.software.common.model.api.GeneralFile;
@ -46,6 +47,7 @@ public class ConvertMarkdownToPdf {
private final CustomHtmlSanitizer customHtmlSanitizer;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/markdown/pdf")
@StandardPdfResponse
@Operation(
summary = "Convert a Markdown file to PDF",
description =

View File

@ -9,6 +9,7 @@ import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import stirling.software.SPDF.config.swagger.HtmlConversionResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.util.PDFToFile;
@ -23,6 +24,7 @@ public class ConvertPDFToHtml {
summary = "Convert PDF to HTML",
description =
"This endpoint converts a PDF file to HTML format. Input:PDF Output:HTML Type:SISO")
@HtmlConversionResponse
public ResponseEntity<byte[]> processPdfToHTML(@ModelAttribute PDFFile file) throws Exception {
MultipartFile inputFile = file.getFileInput();
PDFToFile pdfToFile = new PDFToFile();

View File

@ -17,6 +17,10 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.PowerPointConversionResponse;
import stirling.software.SPDF.config.swagger.TextPlainConversionResponse;
import stirling.software.SPDF.config.swagger.WordConversionResponse;
import stirling.software.SPDF.config.swagger.XmlConversionResponse;
import stirling.software.SPDF.model.api.converters.PdfToPresentationRequest;
import stirling.software.SPDF.model.api.converters.PdfToTextOrRTFRequest;
import stirling.software.SPDF.model.api.converters.PdfToWordRequest;
@ -35,6 +39,7 @@ public class ConvertPDFToOffice {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/presentation")
@PowerPointConversionResponse
@Operation(
summary = "Convert PDF to Presentation format",
description =
@ -50,6 +55,7 @@ public class ConvertPDFToOffice {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/text")
@TextPlainConversionResponse
@Operation(
summary = "Convert PDF to Text or RTF format",
description =
@ -78,6 +84,7 @@ public class ConvertPDFToOffice {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/word")
@WordConversionResponse
@Operation(
summary = "Convert PDF to Word document",
description =
@ -92,6 +99,7 @@ public class ConvertPDFToOffice {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/xml")
@XmlConversionResponse
@Operation(
summary = "Convert PDF to XML",
description =

View File

@ -65,6 +65,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.converters.PdfToPdfARequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.util.ExceptionUtils;
@ -79,6 +80,7 @@ import stirling.software.common.util.WebResponseUtils;
public class ConvertPDFToPDFA {
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/pdf/pdfa")
@StandardPdfResponse
@Operation(
summary = "Convert a PDF to a PDF/A",
description =

View File

@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.converters.UrlToPdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.configuration.RuntimePathConfig;
@ -41,6 +42,7 @@ public class ConvertWebsiteToPDF {
private final ApplicationProperties applicationProperties;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/url/pdf")
@StandardPdfResponse
@Operation(
summary = "Convert a URL to a PDF",
description =

View File

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.FilterResponse;
import stirling.software.SPDF.model.api.PDFComparisonAndCount;
import stirling.software.SPDF.model.api.PDFWithPageNums;
import stirling.software.SPDF.model.api.filter.ContainsTextRequest;
@ -38,6 +39,7 @@ public class FilterController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-contains-text")
@FilterResponse
@Operation(
summary = "Checks if a PDF contains set text, returns true if does",
description = "Input:PDF Output:Boolean Type:SISO")
@ -56,6 +58,7 @@ public class FilterController {
// TODO
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-contains-image")
@FilterResponse
@Operation(
summary = "Checks if a PDF contains an image",
description = "Input:PDF Output:Boolean Type:SISO")
@ -72,6 +75,7 @@ public class FilterController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-count")
@FilterResponse
@Operation(
summary = "Checks if a PDF is greater, less or equal to a setPageCount",
description = "Input:PDF Output:Boolean Type:SISO")
@ -105,6 +109,7 @@ public class FilterController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-size")
@FilterResponse
@Operation(
summary = "Checks if a PDF is of a certain size",
description = "Input:PDF Output:Boolean Type:SISO")
@ -148,6 +153,7 @@ public class FilterController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-file-size")
@FilterResponse
@Operation(
summary = "Checks if a PDF is a set file size",
description = "Input:PDF Output:Boolean Type:SISO")
@ -181,6 +187,7 @@ public class FilterController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/filter-page-rotation")
@FilterResponse
@Operation(
summary = "Checks if a PDF is of a certain rotation",
description = "Input:PDF Output:Boolean Type:SISO")

View File

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.misc.AddAttachmentRequest;
import stirling.software.SPDF.service.AttachmentServiceInterface;
import stirling.software.common.annotations.AutoJobPostMapping;
@ -35,6 +36,7 @@ public class AttachmentController {
private final AttachmentServiceInterface pdfAttachmentService;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-attachments")
@StandardPdfResponse
@Operation(
summary = "Add attachments to PDF",
description =

View File

@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.misc.AutoSplitPdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -103,6 +104,7 @@ public class AutoSplitPdfController {
}
@AutoJobPostMapping(value = "/auto-split-pdf", consumes = "multipart/form-data")
@MultiFileResponse
@Operation(
summary = "Auto split PDF pages into separate documents",
description =

View File

@ -50,6 +50,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.misc.OptimizePdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -659,6 +660,7 @@ public class CompressController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/compress-pdf")
@StandardPdfResponse
@Operation(
summary = "Optimize PDF file",
description =

View File

@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.api.PDFExtractImagesRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -55,6 +56,7 @@ public class ExtractImagesController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/extract-images")
@MultiFileResponse
@Operation(
summary = "Extract images from a PDF file",
description =

View File

@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.misc.FlattenRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -39,6 +40,7 @@ public class FlattenController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/flatten")
@StandardPdfResponse
@Operation(
summary = "Flatten PDF form fields or full page",
description =

View File

@ -22,6 +22,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.misc.MetadataRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -53,6 +54,7 @@ public class MetadataController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/update-metadata")
@StandardPdfResponse
@Operation(
summary = "Update metadata of a PDF file",
description =

View File

@ -30,6 +30,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.misc.ProcessPdfWithOcrRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.ApplicationProperties;
@ -77,6 +78,7 @@ public class OCRController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/ocr-pdf")
@StandardPdfResponse
@Operation(
summary = "Process a PDF file with OCR",
description =

View File

@ -18,6 +18,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.EndpointConfiguration;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -47,6 +48,7 @@ public class RepairController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/repair")
@StandardPdfResponse
@Operation(
summary = "Repair a PDF file",
description =

View File

@ -21,6 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -38,6 +39,7 @@ public class UnlockPDFFormsController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/unlock-pdf-forms")
@StandardPdfResponse
@Operation(
summary = "Remove read-only property from form fields",
description =

View File

@ -20,11 +20,16 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.MultiFileResponse;
import stirling.software.SPDF.model.PipelineConfig;
import stirling.software.SPDF.model.PipelineOperation;
import stirling.software.SPDF.model.PipelineResult;
@ -47,6 +52,45 @@ public class PipelineController {
private final PostHogService postHogService;
@AutoJobPostMapping(value = "/handleData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@MultiFileResponse
@Operation(
summary = "Execute automated PDF processing pipeline",
description =
"This endpoint processes multiple PDF files through a configurable pipeline of operations. "
+ "Users provide files and a JSON configuration defining the sequence of operations to perform. "
+ "Input:PDF Output:PDF/ZIP Type:MIMO")
@RequestBody(
content =
@Content(
mediaType = "multipart/form-data",
examples =
@ExampleObject(
name = "Email Preparation Pipeline",
summary =
"Repair, sanitize, and compress PDFs for email",
value =
"{\n"
+ " \"name\": \"Prepare-pdfs-for-email\",\n"
+ " \"pipeline\": [\n"
+ " {\n"
+ " \"operation\": \"/api/v1/misc/repair\",\n"
+ " \"parameters\": {}\n"
+ " },\n"
+ " {\n"
+ " \"operation\": \"/api/v1/security/sanitize-pdf\",\n"
+ " \"parameters\": {\n"
+ " \"removeJavaScript\": true,\n"
+ " \"removeEmbeddedFiles\": false\n"
+ " }\n"
+ " },\n"
+ " {\n"
+ " \"operation\": \"/api/v1/misc/compress-pdf\",\n"
+ " \"parameters\": {\n"
+ " \"optimizeLevel\": 2\n"
+ " }\n"
+ " }\n"
+ " ]\n"
+ "}")))
public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request)
throws JsonMappingException, JsonProcessingException {
MultipartFile[] files = request.getFileInput();

View File

@ -71,10 +71,11 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.security.SignPDFWithCertRequest;
import stirling.software.common.service.ServerCertificateService;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.service.ServerCertificateService;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.WebResponseUtils;
@ -140,9 +141,8 @@ public class CertSignController {
}
}
@AutoJobPostMapping(
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
value = "/cert-sign")
@AutoJobPostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/cert-sign")
@StandardPdfResponse
@Operation(
summary = "Sign PDF with a Digital Certificate",
description =

View File

@ -60,6 +60,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.JsonDataResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -189,6 +190,7 @@ public class GetInfoOnPDF {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/get-info-on-pdf")
@JsonDataResponse
@Operation(summary = "Summary here", description = "desc. Input:PDF Output:JSON Type:SISO")
public ResponseEntity<byte[]> getPdfInfo(@ModelAttribute PDFFile request) throws IOException {
MultipartFile inputFile = request.getFileInput();

View File

@ -17,6 +17,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.security.AddPasswordRequest;
import stirling.software.SPDF.model.api.security.PDFPasswordRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
@ -33,6 +34,7 @@ public class PasswordController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-password")
@StandardPdfResponse
@Operation(
summary = "Remove password from a PDF file",
description =
@ -59,6 +61,7 @@ public class PasswordController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-password")
@StandardPdfResponse
@Operation(
summary = "Add password to a PDF file",
description =

View File

@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.PDFText;
import stirling.software.SPDF.model.api.security.ManualRedactPdfRequest;
import stirling.software.SPDF.model.api.security.RedactPdfRequest;
@ -57,6 +58,7 @@ public class RedactController {
}
@AutoJobPostMapping(value = "/redact", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
operationId = "redactPdfManual",
summary = "Redacts areas and pages in a PDF document",
@ -192,6 +194,7 @@ public class RedactController {
}
@AutoJobPostMapping(value = "/auto-redact", consumes = "multipart/form-data")
@StandardPdfResponse
@Operation(
operationId = "redactPdfAuto",
summary = "Redacts listOfText in a PDF document",

View File

@ -19,6 +19,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.model.api.PDFFile;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -33,6 +34,7 @@ public class RemoveCertSignController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/remove-cert-sign")
@StandardPdfResponse
@Operation(
summary = "Remove digital signature from PDF",
description =

View File

@ -33,6 +33,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.security.SanitizePdfRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -47,6 +48,7 @@ public class SanitizeController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/sanitize-pdf")
@StandardPdfResponse
@Operation(
summary = "Sanitize a PDF file",
description =

View File

@ -36,6 +36,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.JsonDataResponse;
import stirling.software.SPDF.model.api.security.SignatureValidationRequest;
import stirling.software.SPDF.model.api.security.SignatureValidationResult;
import stirling.software.SPDF.service.CertificateValidationService;
@ -64,6 +65,7 @@ public class ValidateSignatureController {
});
}
@JsonDataResponse
@Operation(
summary = "Validate PDF Digital Signature",
description =

View File

@ -38,6 +38,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
import stirling.software.SPDF.model.api.security.AddWatermarkRequest;
import stirling.software.common.annotations.AutoJobPostMapping;
import stirling.software.common.service.CustomPDFDocumentFactory;
@ -65,6 +66,7 @@ public class WatermarkController {
}
@AutoJobPostMapping(consumes = "multipart/form-data", value = "/add-watermark")
@StandardPdfResponse
@Operation(
summary = "Add watermark to a PDF file",
description =

View File

@ -9,7 +9,6 @@ import org.springframework.ui.Model;
import org.springframework.web.servlet.ModelAndView;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

View File

@ -37,4 +37,4 @@ public class BookletImpositionRequest extends PDFFile {
requiredMode = Schema.RequiredMode.REQUIRED,
allowableValues = {"LANDSCAPE", "PORTRAIT"})
private String pageOrientation = "LANDSCAPE";
}
}

View File

@ -26,7 +26,8 @@ import stirling.software.common.configuration.InstallationPathConfig;
@Service
@Slf4j
public class ServerCertificateService implements stirling.software.common.service.ServerCertificateService {
public class ServerCertificateService
implements stirling.software.common.service.ServerCertificateService {
private static final String KEYSTORE_FILENAME = "server-certificate.p12";
private static final String KEYSTORE_ALIAS = "stirling-pdf-server";
@ -212,5 +213,4 @@ public class ServerCertificateService implements stirling.software.common.servic
keyStore.store(fos, DEFAULT_PASSWORD.toCharArray());
}
}
}
}