How can I help you?
Saving PDF Files in the React PDF Viewer
10 Mar 202617 minutes to read
After editing a PDF with annotation tools, you can save the updated file to a server, a database, or download it locally. The following sections show common approaches.
Save and Download the Edited PDF
After editing the PDF document, follow this short, linear flow to persist and retrieve the updated file:
- Persist the edited document to your back end (server or database). See “Save modified PDF to server” and “Save modified PDF to a database” below for server-side examples.
- Provide the updated file to the user. For a simple download use the built-in toolbar or call the viewer API
download(). - If you need the edited PDF for custom uploads or processing, use the viewer
saveAsBlob()API to obtain a Blob (or convert it to Base64).
This is a summary; use the detailed subsections below for full code samples and server-side instructions.
Save modified PDF to server
To save the modified PDF back to a server, follow these steps.
Step 1: Create a simple PDF Viewer sample in React
Follow the getting-started guide to create a basic PDF Viewer implementation.
Step 2: Modify the PdfViewerController.cs in the web service project
-
Create a web service project targeting .NET Core 3.0 or later. See this KB Link for details.
-
Open the
PdfViewerController.csfile in your web service project. -
Modify the
Download()method so it returns the modified document for the viewer to download or store.
public IActionResult Download([FromBody] Dictionary<string, string> jsonObject)
{
//Initialize the PDF Viewer object with memory cache object
PdfRenderer pdfviewer = new PdfRenderer(_cache);
string documentBase = pdfviewer.GetDocumentAsBase64(jsonObject);
MemoryStream stream = new MemoryStream();
string documentName = jsonObject["document"];
string result = Path.GetFileNameWithoutExtension(documentName);
string fileName = result + "_downloaded.pdf";
// Save the file on the server
string serverFilePath = @"Path to where you need to save your file in the server";
string filePath = Path.Combine(serverFilePath, fileName);
using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
{
//Saving the new file in root path of application
stream.CopyTo(fileStream);
fileStream.Close();
}
return Content(documentBase);
}Step 3: Set the PDF Viewer properties in your React app
Set the serviceUrl to point to your web service (for example, replace https://localhost:44396/pdfviewer with your server URL). Also set documentPath to the document URL you want to load.
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, LinkAnnotation, BookmarkView, ThumbnailView,
Print, TextSelection, Annotation, TextSearch, Inject, FormDesigner, FormFields} from '@syncfusion/ej2-react-pdfviewer';
function App() {
return (<div>
<div className='control-section'>
{/* Render the PDF Viewer */}
<PdfViewerComponent
id="container"
// Replace correct PDF Document URL want to load
documentPath="https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf"
serviceUrl="https://localhost:44396/pdfviewer"
style={{ 'height': '640px' }}>
<Inject services={[ Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView, ThumbnailView,
Print, TextSelection, TextSearch, FormDesigner, FormFields ]} />
</PdfViewerComponent>
</div>
</div>);
}
const root = ReactDOM.createRoot(document.getElementById('sample'));
root.render(<App />);Download PDF file as a copy
The built-in toolbar includes a download option that saves the updated PDF to the user’s local file system. You can also trigger the same behavior programmatically by calling the viewer’s download() API.
import * as ReactDOM from 'react-dom/client';
import * as React from 'react';
import './index.css';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, LinkAnnotation, BookmarkView,
ThumbnailView, Print, TextSelection, Annotation, TextSearch, FormFields, FormDesigner, Inject} from '@syncfusion/ej2-react-pdfviewer';
export function App() {
function downloadClicked() {
var viewer = document.getElementById('container').ej2_instances[0];
viewer.download();
}
return (<div>
<div className='control-section'>
<button onClick={downloadClicked}>Download</button>
<PdfViewerComponent
id="container"
// Replace PDF_Succinctly.pdf with the actual document name that you want to load
documentPath:"PDF_Succinctly.pdf"
// Replace the "localhost:44396" with the actual URL of your server
serviceUrl="https://localhost:44396/pdfviewer"
style={{ 'height': '640px' }}>
{/* Inject the required services */}
<Inject services={[ Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView,
ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner]} />
</PdfViewerComponent>
</div>
</div>);
}
const root = ReactDOM.createRoot(document.getElementById('sample'));
root.render(<App />);Save modified PDF to a database
If your application stores PDF files in a database, you can save the updated PDF bytes back to the database from your web service. The following steps outline a typical server-side flow.
Step 1: Create the React sample viewer
Follow the getting-started guide to set up a basic Viewer instance.
Step 2: Update PdfViewerController.cs in the web service
-
Create a web service project targeting .NET Core 3.0 or later (see the KB link above). Open the
PdfViewerController.csfile in your web service project. -
Import required namespaces:
using System.IO;
using System.Data.SqlClient;- Add configuration fields to your controller and read the connection string from configuration:
private IConfiguration _configuration;
public readonly string _connectionString;
public PdfViewerController(IWebHostEnvironment hostingEnvironment, IMemoryCache cache, IConfiguration configuration)
{
_hostingEnvironment = hostingEnvironment;
_cache = cache;
_configuration = configuration;
_connectionString = _configuration.GetValue<string>("ConnectionString");
}- In the
Download()method, convert the returned base64 document to bytes and insert it into your database (the example below uses parameterized commands to avoid SQL injection):
[HttpPost("Download")]
[Microsoft.AspNetCore.Cors.EnableCors("MyPolicy")]
[Route("[controller]/Download")]
public async Task<IActionResult> Download([FromBody] Dictionary<string, string> jsonObject)
{
//Initialize the PDF Viewer object with memory cache object
PdfRenderer pdfviewer = new PdfRenderer(_cache);
string documentBase = pdfviewer.GetDocumentAsBase64(jsonObject);
byte[] documentBytes = Convert.FromBase64String(documentBase.Split(",")[1]);
string documentId = jsonObject["documentId"];
string result = Path.GetFileNameWithoutExtension(documentId);
string fileName = result + "_downloaded.pdf";
string connectionString = _connectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand("INSERT INTO Table (FileName, fileData) VALUES (@FileName, @fileData)", connection))
{
cmd.Parameters.AddWithValue("@FileName", fileName);
cmd.Parameters.AddWithValue("@fileData", documentBytes);
cmd.ExecuteNonQuery();
}
connection.Close();
}
return Content(documentBase);
}- Add the connection string to
appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionString": "Your connection string for SQL Server"
}NOTE
Replace
Your connection string for SQL Serverwith your actual connection string.
NOTE
Ensure the
System.Data.SqlClientpackage (orMicrosoft.Data.SqlClient) is installed in your project. Use parameterized queries (as shown) and validate inputs to avoid SQL injection risks.
Save to Cloud Storage Services
Each link below goes to a provider page with simple, step-by-step instructions and example code for saving the edited PDF to that cloud storage service.
- AWS S3
- Azure Blob Storage
- Google Cloud Storage
- Google Drive
- OneDrive
- Dropbox
- Box
- Azure AD (auth notes)
Save PDF with or without annotations
The React PDF Viewer allows exporting the current PDF along with annotations, or exporting a clean version without annotations. This gives flexibility depending on workflow review mode, sharing, or securing final documents.
Save PDF with annotations
The PDF is exported with annotations and form fields by default. You can download a PDF using the download button in the built‑in toolbar or through the download API. See the download guide for further explanation.
Save PDF without annotations
The PDF can be exported without annotations by setting the skipDownload API to true in annotationSettings.
<PdfViewerComponent
id="pdfViewer"
documentPath="https://cdn.syncfusion.com/content/pdf/form-filling-document.pdf"
resourceUrl="https://cdn.syncfusion.com/ej2/32.2.5/dist/ej2-pdfviewer-lib"
annotationSettings={{
skipDownload: true
}}
>
<Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, ThumbnailView,
BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Print]} />
</PdfViewerComponent>Save after restoring annotations
PDFs can also be exported after importing annotations. The following code example uses the downloadStart event to cancel the download action and import the annotations from a JSON file before downloading the PDF document.
import {
PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation,
ThumbnailView, BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner,
PageOrganizer, Inject, Print, DownloadStartEventArgs
} from '@syncfusion/ej2-react-pdfviewer';
import { DataFormat, PdfDocument } from '@syncfusion/ej2-pdf';
import { RefObject, useRef } from 'react';
export default function App() {
const viewerRef: RefObject<PdfViewerComponent> = useRef(null);
const blobToBase64 = async (blob: Blob): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error);
reader.onload = () => {
const dataUrl: string = reader.result as string;
const data: string = dataUrl.split(',')[1];
resolve(data);
};
reader.readAsDataURL(blob);
});
}
const restoreAnnotations = async (data: string) => {
try {
const fetchResponse: Response = await fetch("/pdf-succinctly.json", { headers: { Accept: "application/json" } });
if (fetchResponse.ok) {
let document: PdfDocument = new PdfDocument(data);
let jsonData = await fetchResponse.json();
document.importAnnotations(btoa(JSON.stringify(jsonData)), DataFormat.json);
document.save(`${viewerRef.current.fileName}.pdf`);
document.destroy();
}
else {
throw new Error(`HTTP ${fetchResponse.status}`);
}
}
catch (error) {
console.error(error);
}
}
const handleImports = async () => {
const blob: Blob = await viewerRef.current.saveAsBlob();
const data: string = await blobToBase64(blob);
await restoreAnnotations(data);
}
const onDownloadStart = async (args: DownloadStartEventArgs) => {
args.cancel = true;
await handleImports();
};
return (
<div style={{ height: '640px' }}>
<PdfViewerComponent
id="pdf-viewer"
ref={viewerRef}
documentPath="https://cdn.syncfusion.com/content/pdf/form-filling-document.pdf"
resourceUrl="https://cdn.syncfusion.com/ej2/32.2.5/dist/ej2-pdfviewer-lib"
downloadStart={onDownloadStart}
>
<Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, ThumbnailView,
BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Print]} />
</PdfViewerComponent>
</div>
);
}See also