How to Compress PDF File in Salesforce Apex using PDF.co
Sep 2, 2024·10 Minutes Read
In this tutorial, we will show you how to compress PDF files in Salesforce Apex using PDF.co. We will briefly go over the basic steps on Salesforce integration. At the end of the tutorial, you can get a copy the code.
Step 1: Create 3 Remote Sites
First, create three Remote Sites in the Remote Site Settings.
- In the first Remote Site, use the https://api.pdf.co Remote Site URL.
- In the second Remote Site, enter the https://pdf-temp-files.s3.amazonaws.com Remote Site URL.
- In the third Remote Site, add the https://pdf-temp-files.s3.us-west-2.amazonaws.com Remote Site URL.
Step 2: Create 2 Apex Classes
- Click on the gear icon on the top right and open the Developer Console.
- Next, click on File –> New –> Apex Class.
- Enter the Class Name CompressPDFDocument and copy the CompressPDFDocument code.
- Add another Apex Class and name it CompressPDFDocumentTest and copy the CompressPDFDocumentTest code.
Step 3: Add PDF.co API Key
Let’s configure the CompressPDFDocument file.
- Add your PDF.co API Key as API_Key variable’s value. You can get it in your PDF.co dashboard.
- Upload the sample PDF file in Salesforce and use its filename as fileName variable’s value.
- Enter your desired output file name as the DestinationFile variable’s value.
Step 4: Verify the Code
- Then, click on the Debug menu and open the Execute Anonymous Window.
- Enter the
(new CompressPDFDocument()).startProcessing();
code and execute.
Step 5: Search Files
- Now, search Files from the App Launcher.
Step 6: Source Code Files
CompressPDFDocument.cls
public class CompressPDFDocument {
String API_KEY = '**********************';
String fileName = 'sample'; // File name "sample.pdf" which is available in Files.
string DestinationFile = 'result.pdf'; //This is the Desitantion File Name.
public void startProcessing()
{
ContentVersion cv = [select Title, VersionData from ContentVersion where Title = :fileName limit 1];
Blob SourceFile = cv.VersionData;
try
{
//1. Prepare URL for "Get Presigned URL" API call
string url = 'https://api.pdf.co/v1/file/upload/get-presigned-url?contenttype=application/octet-stream&name=:fileName';
HttpRequest req = new HttpRequest();
req.setHeader('x-api-key', API_KEY);
req.setEndpoint(url);
req.setMethod('GET');
req.setTimeout(60000);
Http http = new Http();
HTTPResponse res = http.send(req);
if(res.getStatusCode() == 200)
{
System.Debug('res ' + res);
Map<String, Object> deserializedBody = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
Boolean isError = Boolean.ValueOf(deserializedBody.get('error'));
if(isError == false)
{
// Get URL to use for the file upload
String uploadUrl = String.ValueOf(deserializedBody.get('presignedUrl'));
// Get URL of uploaded file to use with later API calls
String uploadedFileUrl = String.ValueOf(deserializedBody.get('url'));
// 2. UPLOAD THE FILE TO CLOUD.
if(uploadFile(API_KEY, uploadUrl, SourceFile))
{
// 3. Compress Uploaded file and download.
CompressInputPDF(API_KEY, DestinationFile, uploadedFileUrl);
}
}
}
else
{
System.debug('Error Response ' + res.getBody());
System.Debug(' Status ' + res.getStatus());
System.Debug(' Status Code' + res.getStatusCode());
System.Debug(' Response String' + res.toString());
}
}
catch(Exception ex)
{
String errorBody = 'Message: ' + ex.getMessage() + ' -- Cause: ' + ex.getCause() + ' -- Stacktrace: ' + ex.getStackTraceString();
System.Debug(errorBody);
}
}
@TestVisible
public static boolean uploadFile(String API_KEY, String url, Blob sourceFile)
{
HttpRequest req = new HttpRequest();
req.setHeader('x-api-key', API_KEY);
req.setHeader('Content-Type', 'application/octet-stream');
req.setEndpoint(url);
req.setMethod('PUT');
req.setTimeout(60000);
req.setBodyAsBlob(sourceFile);
Http http = new Http();
HTTPResponse res = http.send(req);
if(res.getStatusCode() == 200)
{
System.Debug(res);
return true;
}
else
{
System.debug('Error Response ' + res.getBody());
System.Debug(' Status ' + res.getStatus());
System.Debug(' Status Code' + res.getStatusCode());
System.Debug(' Response String' + res.toString());
return false;
}
}
public static void CompressInputPDF(String API_KEY, String DestinationFile, String uploadedFileUrl)
{
Map<string, object> parameters = new Map<string, object>();
parameters.put('name', DestinationFile);
parameters.put('url', uploadedFileUrl);
string jsonPayload = Json.serialize(parameters);
String url = 'https://api.pdf.co/v1/pdf/optimize';
HttpRequest req = new HttpRequest();
req.setHeader('x-api-key', API_KEY);
req.setHeader('Content-Type', 'application/json');
req.setEndpoint(url);
req.setMethod('POST');
req.setTimeout(60000);
req.setBody(jsonPayload);
Http http = new Http();
HTTPResponse res = http.send(req);
if(res.getStatusCode() == 200)
{
System.Debug(res);
Map<String, Object> deserializedBody = (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
Boolean isError = Boolean.ValueOf(deserializedBody.get('error'));
if(isError == false)
{
String resultFileUrl = String.ValueOf(deserializedBody.get('url'));
downloadPDFAndStore(resultFileUrl, DestinationFile);
}
}
else
{
System.debug('Error Response ' + res.getBody());
System.Debug(' Status ' + res.getStatus());
System.Debug(' Status Code' + res.getStatusCode());
System.Debug(' Response String' + res.toString());
}
}
@TestVisible
private static void downloadPDFAndStore(String extFileUrl, String DestinationFile)
{
Http h = new Http();
HttpRequest req = new HttpRequest();
extFileUrl = extFileUrl.replace(' ', '%20');
req.setEndpoint(extFileUrl);
req.setMethod('GET');
req.setHeader('Content-Type', 'application/pdf');
req.setCompressed(true);
req.setTimeout(60000);
//Now Send HTTP Request
HttpResponse res = h.send(req);
if(res.getStatusCode() == 200)
{
blob fileContent = res.getBodyAsBlob();
ContentVersion conVer = new ContentVersion();
conVer.ContentLocation = 'S'; // to use S specify this document is in Salesforce, to use E for external files
conVer.PathOnClient = DestinationFile + '.pdf'; // The files name, extension is very important here which will help the file in preview.
conVer.Title = DestinationFile; // Display name of the files
conVer.VersionData = fileContent;
insert conVer;
System.Debug('Success');
}
else
{
System.debug('Error Response ' + res.getBody());
System.Debug(' Status ' + res.getStatus());
System.Debug(' Status Code' + res.getStatusCode());
System.Debug(' Response String' + res.toString());
}
}
}
CompressPDFDocumentTest.cls
@isTest
private class CompressPDFDocumentTest
{
@TestSetup
static void makeData(){
ContentVersion conVer = new ContentVersion();
conVer.ContentLocation = 'S'; // to use S specify this document is in Salesforce, to use E for external files
conVer.PathOnClient = 'DestinationFile.pdf'; // The files name, extension is very important here which will help the file in preview.
conVer.Title = 'Sample'; // Display name of the files
conVer.VersionData = Blob.ValueOf('fileContent');
insert conVer;
}
private testmethod static void teststartProcessing()
{
Test.setMock(HttpCalloutMock.class, new CompressPDFDocumentTest.CompressPDFDocumentMock());
CompressPDFDocument dc = new CompressPDFDocument();
Test.startTest();
dc.startProcessing();
Test.stopTest();
List<ContentVersion> cv = new List<ContentVersion>();
cv = [select Id from ContentVersion];
System.assertEquals(2, cv.size());
}
private testmethod static void testuploadFile()
{
Test.setMock(HttpCalloutMock.class, new CompressPDFDocumentTest.CompressPDFDocumentErrorMock());
Test.startTest();
Boolean result = CompressPDFDocument.uploadFile('abc', 'https://www.google.com', Blob.ValueOf('fileContent'));
Test.stopTest();
System.assertEquals(false, result);
}
private testmethod static void teststartProcessingError()
{
CompressPdfDocument dc = new CompressPdfDocument();
Test.startTest();
dc.startProcessing();
Test.stopTest();
List<ContentVersion> cv = new List<ContentVersion>();
cv = [select Id from ContentVersion];
System.assertEquals(1, cv.size());
}
public class CompressPDFDocumentMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
String testBody = '{"presignedUrl":"https://pdf-temp-files.s3-us-west-2.amazonaws.com/0c72bf56341142ba83c8f98b47f14d62/test.pdf?X-Amz-Expires=900&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIZJDPLX6D7EHVCKA/20200302/us-west-2/s3/aws4_request&X-Amz-Date=20200302T143951Z&X-Amz-SignedHeaders=host&X-Amz-Signature=8650913644b6425ba8d52b78634698e5fc8970157d971a96f0279a64f4ba87fc","url":"https://pdf-temp-files.s3-us-west-2.amazonaws.com/0c72bf56341142ba83c8f98b47f14d62/test.pdf?X-Amz-Expires=3600&x-amz-security-token=FwoGZXIvYXdzEGgaDA9KaTOXRjkCdCqSTCKBAW9tReCLk1fVTZBH9exl9VIbP8Gfp1pE9hg6et94IBpNamOaBJ6%2B9Vsa5zxfiddlgA%2BxQ4tpd9gprFAxMzjN7UtjU%2B2gf%2FKbUKc2lfV18D2wXKd1FEhC6kkGJVL5UaoFONG%2Fw2jXfLxe3nCfquMEDo12XzcqIQtNFWXjKPWBkQEvmii4tfTyBTIot4Na%2BAUqkLshH0R7HVKlEBV8btqa0ctBjwzwpWkoU%2BF%2BCtnm8Lm4Eg%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA4NRRSZPHEGHTOA4W/20200302/us-west-2/s3/aws4_request&X-Amz-Date=20200302T143951Z&X-Amz-SignedHeaders=host;x-amz-security-token&X-Amz-Signature=243419ac4a9a315eebc2db72df0817de6a261a684482bbc897f0e7bb5d202bb9","error":false,"status":200,"name":"test.pdf","remainingCredits":98145}';
res.setHeader('Content-Type', 'application/json');
res.setBody(testBody);
res.setStatusCode(200);
return res;
}
}
public class CompressPDFDocumentErrorMock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
String testBody = '{"presignedUrl":"https://pdf-temp-files.s3-us-west-2.amazonaws.com/0c72bf56341142ba83c8f98b47f14d62/test.pdf?X-Amz-Expires=900&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIZJDPLX6D7EHVCKA/20200302/us-west-2/s3/aws4_request&X-Amz-Date=20200302T143951Z&X-Amz-SignedHeaders=host&X-Amz-Signature=8650913644b6425ba8d52b78634698e5fc8970157d971a96f0279a64f4ba87fc","url":"https://pdf-temp-files.s3-us-west-2.amazonaws.com/0c72bf56341142ba83c8f98b47f14d62/test.pdf?X-Amz-Expires=3600&x-amz-security-token=FwoGZXIvYXdzEGgaDA9KaTOXRjkCdCqSTCKBAW9tReCLk1fVTZBH9exl9VIbP8Gfp1pE9hg6et94IBpNamOaBJ6%2B9Vsa5zxfiddlgA%2BxQ4tpd9gprFAxMzjN7UtjU%2B2gf%2FKbUKc2lfV18D2wXKd1FEhC6kkGJVL5UaoFONG%2Fw2jXfLxe3nCfquMEDo12XzcqIQtNFWXjKPWBkQEvmii4tfTyBTIot4Na%2BAUqkLshH0R7HVKlEBV8btqa0ctBjwzwpWkoU%2BF%2BCtnm8Lm4Eg%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA4NRRSZPHEGHTOA4W/20200302/us-west-2/s3/aws4_request&X-Amz-Date=20200302T143951Z&X-Amz-SignedHeaders=host;x-amz-security-token&X-Amz-Signature=243419ac4a9a315eebc2db72df0817de6a261a684482bbc897f0e7bb5d202bb9","error":false,"status":200,"name":"test.pdf","remainingCredits":98145}';
res.setHeader('Content-Type', 'application/json');
res.setBody(testBody);
res.setStatusCode(201);
return res;
}
}
}
Video Guide
Related Tutorials
How to Merge PDF files from Airtable using PDF.co and Make
Sep 9, 2024·5 Minutes Read
Convert DOC to Protected PDF using Make (Formerly Integromat)
Sep 11, 2024·5 Minutes Read