PDF-Formulardaten im Round-Trip: Export und Import mit JavaScript

Wenn ein PDF-Formular ausgefüllt wird, verschmelzen die eingegebenen Werte mit dem visuellen Layout zu einem versiegelten Artefakt. Diese Einträge auf eine andere Vorlage zu übertragen bedeutet, jedes Feld von Hand neu einzugeben. Der Ausweg besteht darin, Formulardaten als portable Ressource zu behandeln: Feldwerte in eine eigenständige Datendatei extrahieren und sie dann wieder in eine leere Kopie des Formulars einzuspeisen, um alle Einträge in einem automatischen Durchlauf zu reproduzieren. Dieser Export-dann-Import-Zyklus ist das, was Spire.PDF für JavaScript durch PdfFormWidget.ExportData und PdfFormWidget.ImportData bietet.
Beide Methoden akzeptieren drei Dateiformate: XML, FDF und XFDF. Das Umschalten zwischen ihnen ist nichts weiter als das Ändern eines DataFormat-Enum-Werts – die Aufrufkonvention bleibt identisch; nur die Struktur der Ausgabedatei auf dem Datenträger ändert sich. Da Spire.PDF für JavaScript vollständig im Browser auf WebAssembly ausgeführt wird, erfolgt der gesamte Round-Trip lokal über ein virtuelles Dateisystem (VFS), ohne dass ein Backend-Server beteiligt ist und ohne dass das Dokument jemals den Client verlässt.
Dieser Artikel führt durch den vollständigen Datenfluss:
- Formulardaten exportieren — Feldwerte aus einem ausgefüllten Formular herausziehen
- Formulardaten importieren — diese Werte zurück in ein leeres Formular einspeisen
Informationen zur Installation und Projekteinrichtung finden Sie unter Spire.PDF für JavaScript in ein React-Projekt integrieren. Die folgenden Beispiele gehen davon aus, dass Spire.PDF installiert und das WebAssembly-Modul initialisiert ist.
Drei Formulardatenformate auf einen Blick
Bevor wir in den Code eintauchen, ist es hilfreich, die drei Formate zu verstehen, mit denen ExportData und ImportData arbeiten. Alle drei tragen die gleiche Nutzlast – eine Reihe von Feldname/Wert-Paaren –, verpacken sie aber auf unterschiedliche Weise. Wenn Sie von Anfang an das richtige auswählen, ersparen Sie sich später Reibung, wenn die Datendatei weitergegeben, überprüft oder in ein anderes Tool eingespeist werden muss.
| Format | Enum-Wert | Dateistruktur | Für Menschen lesbar | Am besten für |
|---|---|---|---|---|
| XML | DataFormat.Xml |
Adobe Formulardaten-XML; der Feldname wird zum Elementnamen, der Wert steht als Elementinhalt | Ja | Schnelle Überprüfung, Debugging, einfache Tools |
| FDF | DataFormat.Fdf |
Forms Data Format; eine Textstruktur, die mit %FDF- beginnt, wobei /T den Feldnamen und /V den Wert enthält |
Nein | Kompakter Datenaustausch zwischen Programmen |
| XFDF | DataFormat.XFdf |
XFDF, Standard-XML; ein <field name="…"> pro Feld, mit dem Wert in <value> |
Ja | Versionskontrolle, systemübergreifender Austausch |
Alle drei sind verlustfrei in Bezug auf die Feldwerte – beim Exportieren oder Importieren wird nichts verworfen oder transformiert. Die Wahl zwischen ihnen hängt ausschließlich von der Workflow-Eignung ab, worauf wir im Leitfaden zur Formatauswahl unten zurückkommen.
PDF-Formulardaten exportieren
Die erste Hälfte des Round-Trips ist die Extraktion. PdfFormWidget.ExportData nimmt jeden Feldwert im Formular und schreibt ihn in eine einzige Datendatei. Das zweite Argument – ein DataFormat-Enum – steuert, welches Format geschrieben wird. Das dritte Argument ist der Formularname; für ein unbenanntes AcroForm übergeben Sie eine leere Zeichenfolge.
Das folgende Beispiel lädt ein ausgefülltes Kundeninformationsformular, packt sein Formularhandle in ein PdfFormWidget und exportiert die Feldwerte in eine XML-Datei. Die FDF- und XFDF-Varianten sind als auskommentierte Zeilen enthalten – kommentieren Sie eine davon aus, um das Format zu wechseln, ohne etwas anderes zu ändern:
function App() {
const exportFormData = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be exported into the VFS
const inputFileName = 'CustomerInformationForm.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Build a PdfFormWidget from the document's form handle to reach the data export API
const formWidget = new pdfModule.PdfFormWidget(doc.Form.H);
// This demo exports XML
const dataFiles = [
{ fileName: 'FormData.xml', format: pdfModule.DataFormat.Xml },
// { fileName: 'FormData.fdf', format: pdfModule.DataFormat.Fdf },
// { fileName: 'FormData.xfdf', format: pdfModule.DataFormat.XFdf },
];
for (const item of dataFiles) {
// The third parameter is the form name; pass an empty string for an unnamed form
formWidget.ExportData(item.fileName, item.format, '');
}
doc.Close();
// Read the generated file from the VFS and trigger the download
for (const item of dataFiles) {
const fileArray = window.dotnetRuntime.Module.FS.readFile(item.fileName);
const blob = new Blob([fileArray], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = item.fileName;
a.click();
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Export Form Data</h1>
<button onClick={exportFormData}>
Export
</button>
</div>
);
}
export default App;
Sobald der Exportaufruf abgeschlossen ist, befindet sich die Datendatei im virtuellen Dateisystem. Der Code liest sie dann aus dem VFS zurück und löst einen Browser-Download aus, damit die Datei gespeichert, weitergegeben oder zusammen mit anderen Formulardaten archiviert werden kann:

PDF-Formulardaten importieren
Die zweite Hälfte des Round-Trips ist die Rehydrierung. PdfFormWidget.ImportData liest eine Datendatei und schreibt jeden Wert anhand des Namens zurück in das passende Formularfeld. Der Parameter DataFormat teilt dem Parser mit, wie der Dateiinhalt zu interpretieren ist – er hat nichts mit der Dateiendung zu tun, daher muss das angegebene Format mit dem tatsächlichen Format der Datei übereinstimmen.
Das Ziel hier ist eine leere Kopie des Originalformulars. Die Vorlage wird leer ausgegeben; wenn die Datendatei zurückkommt, wird jedes Feld in einem einzigen Durchlauf befüllt – keine manuelle Neueingabe, kein Kopieren Feld für Feld, kein erneutes Eingeben aller Daten:
function App() {
const importFormData = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the blank form to be filled into the VFS
const inputFileName = 'BlankCustomerInformationForm.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// This demo refills from the XML data file
const dataFiles = [
{ fileName: 'FormData.xml', format: pdfModule.DataFormat.Xml, outputFileName: 'ImportedXMLData.pdf' },
// { fileName: 'FormData.fdf', format: pdfModule.DataFormat.Fdf, outputFileName: 'ImportedFDFData.pdf' },
// { fileName: 'FormData.xfdf', format: pdfModule.DataFormat.XFdf, outputFileName: 'ImportedXFDFData.pdf' },
];
for (const item of dataFiles) {
// The data file also has to be loaded into the VFS first
await window.spire.FetchFileToVFS(item.fileName, "", `${process.env.PUBLIC_URL}/data/`);
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Read the data file and write the values back into the fields by name
const formWidget = new pdfModule.PdfFormWidget(doc.Form.H);
formWidget.ImportData(item.fileName, item.format);
doc.SaveToFile(item.outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(item.outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = item.outputFileName;
a.click();
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Import Form Data</h1>
<button onClick={importFormData}>
Import
</button>
</div>
);
}
export default App;
Nach Abschluss des Importaufrufs ist das zuvor leere Formular vollständig befüllt und bereit, gespeichert oder angezeigt zu werden. Das Ergebnis ist ein neues PDF, bei dem jedes Feld aus der Datendatei ausgefüllt ist:

Das richtige Datenformat auswählen
Alle drei Formate enthalten identische Feldwerte, sodass die Entscheidung auf Struktur und Tool-Unterstützung hinausläuft und nicht auf Datentreue. So sollten Sie jedes einzelne im Kontext eines Formulardaten-Round-Trips betrachten:
- FDF erzeugt die kleinsten Dateien. Es beginnt mit
%FDF-und verwendet eine kompakte Textnotation, bei der/Tden Feldnamen und/Vden Wert trägt. Dadurch ist es effizient für die Übergabe von Daten zwischen formularverarbeitenden Programmen, aber der Inhalt ist für Menschen nicht leicht zu lesen und harmoniert nicht gut mit Textwerkzeugen oder Versionskontrollsystemen. - XFDF ist Standard-XML mit einem
<field>-Element pro Feld. Da es sich um wohlgeformtes XML handelt, kann es mit gewöhnlichen Textwerkzeugen verglichen, zusammengeführt und überprüft werden, was es zur sichersten Wahl macht, wenn die Datendatei in die Versionskontrolle eingeht, von Menschen überprüft werden muss oder mit einem anderen System interoperieren soll. - XML (Adobe Formulardaten-XML) setzt den Feldnamen direkt in den Elementnamen, was die geradlinigste Struktur der drei ergibt. Es ist ideal, wenn Sie einfach eine lesbare Liste von Feldnamen und -werten ohne zusätzlichen Aufwand wünschen.
Kurz gesagt: Verwenden Sie FDF für Round-Trips, die innerhalb eines einzigen Programms bleiben; verwenden Sie XFDF, wenn die Datei Tool- oder Teamgrenzen überschreitet; verwenden Sie XML, wenn Lesbarkeit oberste Priorität hat.
FAQ
Einige Felder sind nach dem Import noch leer
Ursache: ImportData gleicht nach Feldnamen ab, daher müssen die Namen in der Datendatei exakt mit den Feldnamen im Formular übereinstimmen – einschließlich Groß-/Kleinschreibung und Leerzeichen. Ein Feld, das nicht übereinstimmt, wird stillschweigend übersprungen; es gibt keinen Fehler und keinen Rückgabewert, der auf eine Nichtübereinstimmung hinweist. Nur die Felder, deren Namen übereinstimmen, erhalten einen Wert.
Lösung: Bevor Sie importieren, durchlaufen Sie die Feldauflistung des Formulars und geben Sie die tatsächlichen Namen aus, und vergleichen Sie sie dann mit der Datendatei:
const fields = formWidget.FieldsWidget;
for (let i = 0; i < fields.Count; i++) {
console.log(fields.get_Item({ index: i }).Name);
}
Import löst Xml_MessageWithErrorPosition oder "not a valid FDF file" aus
Ursache: ImportData analysiert die Datei gemäß dem durch den zweiten Parameter angegebenen Format und prüft niemals die Dateiendung. Wenn der Inhalt nicht mit dem angegebenen Format übereinstimmt, schlägt das Parsen sofort fehl: XML-Dateien melden Xml_MessageWithErrorPosition, Xml_InvalidRootData, und eine Nicht-FDF-Datei meldet The source is not a valid FDF file because it does not start with "%FDF-".
Lösung: Übergeben Sie das DataFormat, das dem tatsächlichen Inhalt der Datei entspricht, und verwenden Sie die ursprüngliche exportierte Datendatei anstelle einer, die in einem anderen Format neu gespeichert wurde.
Siehe auch
Круговой обмен данными PDF-формы: экспорт и импорт с помощью JavaScript

Когда форма PDF заполнена, введённые значения сливаются с визуальной компоновкой в единый артефакт. Перенос этих записей в другой шаблон означает повторный ручной ввод каждого поля. Выход — относиться к данным формы как к переносимому ресурсу: извлечь значения полей в отдельный файл данных, а затем подать его обратно в пустой экземпляр формы, чтобы воспроизвести все записи за один автоматический проход. Именно этот цикл «экспорт — импорт» реализует Spire.PDF for JavaScript через PdfFormWidget.ExportData и PdfFormWidget.ImportData.
Оба метода принимают три формата файлов: XML, FDF и XFDF. Переключение между ними — это не более чем изменение значения перечисления DataFormat: способ вызова остаётся тем же, меняется лишь структура выходного файла на диске. Поскольку Spire.PDF for JavaScript полностью работает в браузере на основе WebAssembly, весь цикл выполняется локально через виртуальную файловую систему (VFS), без участия серверной части, и документ никогда не покидает клиент.
В этой статье рассматривается полный поток данных:
- Экспорт данных формы — извлечение значений полей из заполненной формы
- Импорт данных формы — запись этих значений обратно в пустую форму
Информацию об установке и настройке проекта см. в разделе Интеграция Spire.PDF for JavaScript в проект React. В приведённых ниже примерах предполагается, что Spire.PDF установлен и модуль WebAssembly инициализирован.
Три формата данных форм: краткий обзор
Прежде чем переходить к коду, полезно разобраться в трёх форматах, с которыми работают ExportData и ImportData. Все три несут одну и ту же полезную нагрузку — набор пар «имя поля / значение», — но упаковывают её по-разному. Если выбрать подходящий формат сразу, позже будет меньше сложностей, когда файл данных потребуется передать, проверить или подать в другой инструмент.
| Формат | Значение перечисления | Структура файла | Читаемость для человека | Лучше всего подходит для |
|---|---|---|---|---|
| XML | DataFormat.Xml |
XML данных формы Adobe; имя поля становится именем элемента, а значение — содержимым элемента | Да | Быстрого просмотра, отладки, простых инструментов |
| FDF | DataFormat.Fdf |
Forms Data Format; текстовая структура, начинающаяся с %FDF-, где /T содержит имя поля, а /V — значение |
Нет | Компактной передачи между программами |
| XFDF | DataFormat.XFdf |
XFDF, стандартный XML; один <field name="…"> на каждое поле, значение внутри <value> |
Да | Контроля версий, обмена между системами |
Все три формата не теряют значения полей — при экспорте и импорте ничего не отбрасывается и не преобразуется. Выбор между ними определяется исключительно удобством рабочего процесса, к чему мы вернёмся в руководстве по выбору формата ниже.
Экспорт данных формы PDF
Первая половина цикла — извлечение. PdfFormWidget.ExportData берёт все значения полей формы и записывает их в один файл данных. Второй аргумент — перечисление DataFormat — определяет, в каком формате будет выполнена запись. Третий аргумент — имя формы; для неименованной AcroForm передайте пустую строку.
В приведённом ниже примере загружается заполненная форма сведений о клиенте, её дескриптор формы оборачивается в PdfFormWidget, а значения полей экспортируются в файл XML. Варианты для FDF и XFDF добавлены в виде закомментированных строк — раскомментируйте любую из них, чтобы сменить формат, не трогая ничего остального:
function App() {
const exportFormData = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be exported into the VFS
const inputFileName = 'CustomerInformationForm.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Build a PdfFormWidget from the document's form handle to reach the data export API
const formWidget = new pdfModule.PdfFormWidget(doc.Form.H);
// This demo exports XML
const dataFiles = [
{ fileName: 'FormData.xml', format: pdfModule.DataFormat.Xml },
// { fileName: 'FormData.fdf', format: pdfModule.DataFormat.Fdf },
// { fileName: 'FormData.xfdf', format: pdfModule.DataFormat.XFdf },
];
for (const item of dataFiles) {
// The third parameter is the form name; pass an empty string for an unnamed form
formWidget.ExportData(item.fileName, item.format, '');
}
doc.Close();
// Read the generated file from the VFS and trigger the download
for (const item of dataFiles) {
const fileArray = window.dotnetRuntime.Module.FS.readFile(item.fileName);
const blob = new Blob([fileArray], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = item.fileName;
a.click();
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Export Form Data</h1>
<button onClick={exportFormData}>
Export
</button>
</div>
);
}
export default App;
После завершения вызова экспорта файл данных находится в виртуальной файловой системе. Затем код считывает его из VFS и запускает загрузку в браузере, чтобы файл можно было сохранить, передать или заархивировать вместе с другими данными форм:

Импорт данных формы PDF
Вторая половина цикла — восстановление данных. PdfFormWidget.ImportData считывает файл данных и записывает каждое значение обратно в соответствующее поле формы по имени. Параметр DataFormat указывает парсеру, как интерпретировать содержимое файла; он никак не связан с расширением файла, поэтому объявленный формат должен совпадать с фактическим форматом файла.
Целевым объектом здесь является пустой экземпляр исходной формы. Шаблон отправляется незаполненным; когда файл данных возвращается, все поля заполняются за один проход — без повторного ручного ввода, без копирования поле за полем, без необходимости вводить всё заново:
function App() {
const importFormData = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the blank form to be filled into the VFS
const inputFileName = 'BlankCustomerInformationForm.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// This demo refills from the XML data file
const dataFiles = [
{ fileName: 'FormData.xml', format: pdfModule.DataFormat.Xml, outputFileName: 'ImportedXMLData.pdf' },
// { fileName: 'FormData.fdf', format: pdfModule.DataFormat.Fdf, outputFileName: 'ImportedFDFData.pdf' },
// { fileName: 'FormData.xfdf', format: pdfModule.DataFormat.XFdf, outputFileName: 'ImportedXFDFData.pdf' },
];
for (const item of dataFiles) {
// The data file also has to be loaded into the VFS first
await window.spire.FetchFileToVFS(item.fileName, "", `${process.env.PUBLIC_URL}/data/`);
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Read the data file and write the values back into the fields by name
const formWidget = new pdfModule.PdfFormWidget(doc.Form.H);
formWidget.ImportData(item.fileName, item.format);
doc.SaveToFile(item.outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(item.outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = item.outputFileName;
a.click();
URL.revokeObjectURL(url);
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Import Form Data</h1>
<button onClick={importFormData}>
Import
</button>
</div>
);
}
export default App;
После завершения вызова импорта ранее пустая форма полностью заполнена и готова к сохранению или отображению. Результат — новый PDF, в котором каждое поле заполнено данными из файла данных:

Выбор подходящего формата данных
Все три формата содержат идентичные значения полей, поэтому решение сводится к структуре и поддержке инструментами, а не к точности данных. Вот как следует думать о каждом из них в контексте цикла экспорта-импорта данных формы:
- FDF создаёт файлы наименьшего размера. Он начинается с
%FDF-и использует компактную текстовую нотацию, где/Tсодержит имя поля, а/V— значение. Это делает его эффективным для передачи данных между программами, работающими с формами, однако содержимое нелегко прочитать человеку, и он плохо сочетается с текстовыми инструментами и системами контроля версий. - XFDF — это стандартный XML с одним элементом
<field>на каждое поле. Поскольку это корректно сформированный XML, его можно сравнивать, объединять и просматривать обычными текстовыми инструментами, что делает его самым безопасным выбором, когда файл данных попадает в систему контроля версий, требует проверки человеком или должен взаимодействовать с другой системой. - XML (XML данных формы Adobe) помещает имя поля непосредственно в имя элемента, обеспечивая самую простую структуру из трёх. Он идеален, когда нужно просто получить читаемый список имён полей и значений без лишних формальностей.
Коротко: используйте FDF для циклов, которые остаются внутри одной программы; XFDF — когда файл пересекает границы инструментов или команд; XML — когда читаемость является главным приоритетом.
Часто задаваемые вопросы
Некоторые поля остаются пустыми после импорта
Причина: ImportData сопоставляет данные по имени поля, поэтому имена в файле данных должны в точности совпадать с именами полей в форме — включая регистр и пробелы. Поле, которое не совпало, молча пропускается; ошибки нет и нет возвращаемого значения, указывающего на несовпадение. Значение получают только те поля, чьи имена совпали.
Решение: Перед импортом пройдите по коллекции полей формы и выведите их фактические имена, затем сравните их с файлом данных:
const fields = formWidget.FieldsWidget;
for (let i = 0; i < fields.Count; i++) {
console.log(fields.get_Item({ index: i }).Name);
}
При импорте возникает ошибка Xml_MessageWithErrorPosition или «not a valid FDF file»
Причина: ImportData разбирает файл в соответствии с форматом, указанным во втором параметре, и никогда не проверяет расширение файла. Когда содержимое не соответствует объявленному формату, разбор немедленно завершается ошибкой: для XML-файлов сообщается Xml_MessageWithErrorPosition, Xml_InvalidRootData, а для файла, не являющегося FDF, — The source is not a valid FDF file because it does not start with "%FDF-".
Решение: Передайте DataFormat, соответствующий фактическому содержимому файла, и используйте исходный экспортированный файл данных, а не тот, который был повторно сохранён в другом формате.
См. также
Aparar Páginas PDF: Recorte Margens e Espaços em Branco com JavaScript

Os PDFs frequentemente carregam mais espaço em branco do que o necessário — documentos digitalizados com bordas espessas, desenhos de engenharia com margens generosas ou faturas em que apenas a tabela central importa. Recortar a página é a correção natural, mas fazer isso em um fluxo de trabalho baseado em navegador não é simples. Ferramentas de desktop quebram a experiência web, e enviar o arquivo para um servidor de back-end levanta preocupações de privacidade e conformidade.
É aqui que o Spire.PDF for JavaScript entra. Ele é executado em WebAssembly e opera inteiramente dentro do navegador, carregando e salvando PDFs por meio de um sistema de arquivos virtual (VFS) sem ida e volta ao servidor. Você pode definir a área visível de cada página programaticamente e permitir que o usuário baixe o resultado recortado — tudo no lado do cliente. Para instalação e configuração do projeto, consulte Integrar o Spire.PDF for JavaScript em um projeto React. Os exemplos abaixo pressupõem que o Spire.PDF está instalado e o módulo WebAssembly está inicializado.
CropBox e MediaBox: Duas Caixas de Página Explicadas
Cada página de PDF é definida por dois retângulos, e entender a diferença entre eles é essencial antes de começar a recortar.
MediaBox descreve as dimensões físicas da página — a folha de papel inteira, por assim dizer. É o limite mais externo e define o espaço de coordenadas no qual todo o conteúdo é posicionado. Uma página A4 padrão tem um MediaBox de aproximadamente 595 × 842 pontos.
CropBox define o que o visualizador realmente exibe. É uma sub-região do MediaBox, e qualquer conteúdo que fique fora do CropBox é ocultado da visualização. Por padrão, o CropBox corresponde ao MediaBox, e é por isso que normalmente você vê a página inteira. Quando você reduz o CropBox, está efetivamente dizendo ao leitor de PDF: "Mostre apenas esta parte da página."
O ponto-chave para o recorte é que o CropBox é derivado do MediaBox. Você lê as dimensões completas da página em page.MediaBox.Width e page.MediaBox.Height, depois calcula um retângulo menor — reduzido pela margem que desejar em cada lado — e o atribui a page.CropBox. As coordenadas x e y do CropBox são medidas a partir do canto superior esquerdo da página, e width e height determinam quanto da página é mantido.
Recortar Todas as Páginas com uma Margem Uniforme
O cenário mais comum é aplicar a mesma redução de margem a todas as páginas de um documento. Você itera sobre doc.Pages, lê o MediaBox de cada página e define um CropBox que é reduzido por um número fixo de pontos nos quatro lados.
O exemplo abaixo remove 60 pontos de cada borda de cada página — o suficiente para remover uma borda branca larga ou uma moldura indesejada:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Ambas as páginas são recortadas por uma margem de 60 pontos, de modo que a margem branca e a moldura ao redor da página são removidas:

Ajuste o valor de margin para controlar quão agressivamente a página é recortada. Um valor maior remove mais espaço em branco; um valor menor realiza um recorte mais sutil. Como a margem é aplicada uniformemente aos quatro lados, esta abordagem funciona melhor quando a borda indesejada é aproximadamente igual em todas as extremidades — o que normalmente é o caso de documentos digitalizados e desenhos exportados.
Recorte de Página Única vs Documento Inteiro
O loop da seção anterior aplica o mesmo recorte a todas as páginas. Mas CropBox é uma propriedade em nível de página — não existe uma interface de recorte para todo o documento. O loop simplesmente garante que cada página receba a mesma margem. Essa distinção importa quando suas páginas têm necessidades diferentes.
Quando recortar o documento inteiro: Use a abordagem com loop quando todas as páginas compartilham o mesmo problema — por exemplo, um lote digitalizado em que cada página tem a mesma borda do scanner, ou um conjunto de desenhos de várias páginas exportado com margens idênticas. Um único valor de margin mantém o código simples e o resultado consistente.
Quando recortar uma única página: Remova o loop e atribua o CropBox diretamente à página desejada. Isso é útil quando apenas uma página precisa ser recortada — por exemplo, uma capa com um logotipo superdimensionado, ou uma fatura em que apenas a região da tabela na página 2 deve ser visível. Você também pode aplicar valores de recorte diferentes a páginas diferentes combinando lógica por página dentro do loop.
Veja como recortar apenas a primeira página, mantendo um bloco de 400 × 500 pontos começando na posição (80, 80) a partir do canto superior esquerdo:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Os valores de x e y especificam onde a região visível começa, medidos a partir do canto superior esquerdo da página. Os valores de width e height definem o tamanho dessa região. Tudo fora desse retângulo é ocultado do visualizador.
Recorte Suave: O Que Acontece com o Conteúdo
Há um detalhe importante sobre o CropBox que é fácil de ignorar: ele realiza um recorte suave, não um recorte rígido.
Quando você define o CropBox, está alterando o limite visível da página — o retângulo que os visualizadores de PDF exibem e que as impressoras usam como área da página. Mas o conteúdo que fica fora desse limite não é removido do arquivo. Ele ainda está lá, apenas oculto. Isso tem duas consequências práticas:
O tamanho do arquivo não diminui. O texto, as imagens e os gráficos vetoriais recortados permanecem no fluxo de dados do PDF. Se seu objetivo é reduzir o tamanho do arquivo recortando margens, definir apenas o CropBox não alcançará isso.
O conteúdo recortado ainda é pesquisável. O texto fora do CropBox visível ainda pode ser encontrado por funções de pesquisa e copiado por usuários que sabem como selecionar além da área visível. Isso geralmente é aceitável para recorte de margens, mas significa que o recorte não é uma forma de censurar ou remover com segurança informações sensíveis.
Se você precisa realmente eliminar conteúdo — para censura, redução do tamanho do arquivo ou para garantir que texto oculto não possa ser recuperado —, deve reconstruir a página. A abordagem é criar um novo documento, extrair o conteúdo visível da página recortada usando page.CreateTemplate(), desenhá-lo em uma nova página no novo documento e salvar o resultado. Isso produz um recorte rígido em que o conteúdo fora dos limites não existe mais no arquivo.
Para a maioria dos casos de uso de recorte de margens e remoção de espaços em branco, no entanto, o recorte suave com CropBox é exatamente o que você deseja: é rápido, simples e produz um resultado visualmente limpo sem a sobrecarga de reconstruir o documento.
Perguntas Frequentes
Posso recortar uma única página em vez do documento inteiro?
Sim. Como CropBox é uma propriedade por página, não há um método integrado de "recortar o documento inteiro" — o loop do exemplo principal é apenas uma conveniência para aplicar a mesma margem a todas as páginas. Para recortar apenas uma página, pule o loop e atribua o CropBox diretamente a essa página:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Como desfaço um recorte?
Definir CropBox modifica a caixa da página no local, e o documento não armazena a caixa anterior. Você pode esperar que atribuir page.MediaBox de volta a page.CropBox restaurasse a visualização original, mas isso não funciona como pretendido — as coordenadas são aplicadas em relação à origem da área visível atual, então apenas as dimensões mudam enquanto a origem permanece fixa. Após um recorte de 60 pontos, reatribuir as dimensões do MediaBox ainda deixa a área visível começando em (60, 60).
A solução mais simples é recarregar o arquivo original, se você ainda o tiver. Se apenas o arquivo recortado estiver disponível, você pode deslocar a origem de volta para o canto superior esquerdo usando deslocamentos negativos e restaurar as dimensões completas da página:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
O arquivo não ficou menor e o conteúdo recortado ainda é pesquisável — por quê?
Esse é o comportamento esperado. O CropBox realiza um recorte suave: ele altera apenas o limite visível da página, enquanto o conteúdo fora desse limite permanece no arquivo e ainda pode ser encontrado por pesquisa de texto ou operações de cópia. Se você precisa remover fisicamente o conteúdo do PDF, definir o CropBox não é suficiente — você precisaria reconstruir a página criando um novo documento, extraindo o conteúdo visível com page.CreateTemplate(), desenhando-o em uma nova página e salvando em um novo arquivo.
Veja Também
PDF 페이지 자르기: JavaScript로 여백과 공백 크롭하기

PDF는 필요한 것보다 더 많은 여백을 포함하는 경우가 많습니다 — 두꺼운 테두리가 있는 스캔 문서, 여유로운 여백이 있는 엔지니어링 도면, 또는 중앙의 표만 중요한 인보이스 등이 그렇습니다. 페이지를 자르는 것이 자연스러운 해결책이지만, 브라우저 기반 워크플로에서 이를 수행하는 것은 간단하지 않습니다. 데스크톱 도구는 웹 경험을 깨뜨리고, 파일을 백엔드 서버로 보내는 것은 개인정보 및 규정 준수 문제를 일으킬 수 있습니다.
이때 Spire.PDF for JavaScript가 등장합니다. 이는 WebAssembly에서 실행되며 전적으로 브라우저 내부에서 동작하여, 서버 왕복 없이 가상 파일 시스템(VFS)을 통해 PDF를 로드하고 저장합니다. 각 페이지의 표시 영역을 프로그래밍 방식으로 설정하고 사용자가 잘린 결과를 다운로드하도록 할 수 있습니다 — 모두 클라이언트 측에서 말입니다. 설치 및 프로젝트 설정은 React 프로젝트에서 Spire.PDF for JavaScript 통합하기를 참조하십시오. 아래 예제는 Spire.PDF가 설치되고 WebAssembly 모듈이 초기화되었다고 가정합니다.
CropBox와 MediaBox: 두 가지 페이지 상자 설명
모든 PDF 페이지는 두 개의 사각형으로 정의되며, 자르기를 시작하기 전에 이들 간의 차이를 이해하는 것이 필수적입니다.
MediaBox는 페이지의 물리적 크기, 말하자면 전체 종이를 나타냅니다. 이는 가장 바깥쪽 경계이며 모든 콘텐츠가 배치되는 좌표 공간을 정의합니다. 표준 A4 페이지의 MediaBox는 약 595 × 842포인트입니다.
CropBox는 뷰어가 실제로 표시하는 영역을 정의합니다. 이는 MediaBox의 하위 영역이며, CropBox 밖에 있는 콘텐츠는 보기에서 숨겨집니다. 기본적으로 CropBox는 MediaBox와 일치하므로 일반적으로 전체 페이지가 표시됩니다. CropBox를 줄이면 PDF 리더에게 "페이지의 이 부분만 표시하세요."라고 말하는 것과 같습니다.
자르기의 핵심은 CropBox가 MediaBox에서 파생된다는 점입니다. page.MediaBox.Width와 page.MediaBox.Height에서 전체 페이지 크기를 읽은 다음, 각 변에 원하는 여백만큼 안쪽으로 들어간 더 작은 사각형을 계산하여 page.CropBox에 할당합니다. CropBox의 x 및 y 좌표는 페이지의 왼쪽 위 모서리에서 측정되며, width와 height는 페이지 중 얼마나 유지되는지를 결정합니다.
모든 페이지를 균일한 여백으로 자르기
가장 일반적인 시나리오는 문서의 모든 페이지에 동일한 여백 감소를 적용하는 것입니다. doc.Pages를 반복하면서 각 페이지의 MediaBox를 읽고, 네 변 모두에서 고정된 포인트 수만큼 안쪽으로 들어간 CropBox를 설정합니다.
아래 예제는 모든 페이지의 각 변에서 60포인트를 잘라냅니다 — 넓은 흰색 테두리나 원치 않는 프레임을 제거하기에 충분합니다:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
두 페이지 모두 60포인트 여백으로 잘려서 페이지 주변의 흰색 여백과 프레임이 제거됩니다:

margin 값을 조정하여 페이지가 얼마나 공격적으로 잘릴지 제어합니다. 값이 클수록 더 많은 여백이 제거되고, 값이 작을수록 더 미묘하게 잘립니다. 여백이 네 변 모두에 균일하게 적용되므로, 이 접근 방식은 원치 않는 테두리가 모든 변에서 거의 동일할 때 가장 잘 작동합니다 — 일반적으로 스캔 문서와 내보낸 도면에서 그렇습니다.
단일 페이지 대 전체 문서 자르기
이전 섹션의 루프는 모든 페이지에 동일한 자르기를 적용합니다. 하지만 CropBox는 페이지 수준 속성이므로 문서 전체에 적용되는 자르기 인터페이스는 없습니다. 루프는 단순히 각 페이지가 동일한 여백을 받도록 보장합니다. 이 구분은 페이지마다 요구 사항이 다를 때 중요합니다.
전체 문서를 자를 때: 모든 페이지가 동일한 문제를 공유할 때 루프 접근 방식을 사용하십시오 — 예를 들어 모든 페이지에 동일한 스캐너 테두리가 있는 스캔 배치나, 동일한 여백으로 내보낸 여러 페이지 도면 세트가 그렇습니다. 단일 margin 값을 사용하면 코드가 단순해지고 결과가 일관됩니다.
단일 페이지를 자를 때: 루프를 제거하고 대상 페이지에 CropBox를 직접 할당하십시오. 한 페이지만 잘라야 할 때 유용합니다 — 예를 들어 너무 큰 로고가 있는 표지 페이지나, 2페이지의 표 영역만 표시되어야 하는 인보이스가 그렇습니다. 루프 내부에 페이지별 로직을 결합하여 페이지마다 다른 자르기 값을 적용할 수도 있습니다.
다음은 첫 번째 페이지만 자르는 방법으로, 왼쪽 위 모서리에서 (80, 80) 위치에서 시작하는 400 × 500포인트 블록을 유지합니다:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
x 및 y 값은 페이지의 왼쪽 위 모서리에서 측정된, 표시 영역이 시작하는 위치를 지정합니다. width와 height 값은 해당 영역의 크기를 정의합니다. 이 사각형 밖의 모든 것은 뷰어에서 숨겨집니다.
소프트 자르기: 콘텐츠에 발생하는 일
CropBox에 대해 간과하기 쉬운 중요한 세부 사항이 있습니다: 이는 소프트 자르기를 수행하며, 하드 자르기가 아닙니다.
CropBox를 설정하면 페이지의 표시 경계, 즉 PDF 뷰어가 표시하고 프린터가 페이지 영역으로 사용하는 사각형을 변경하는 것입니다. 하지만 이 경계 밖에 있는 콘텐츠는 파일에서 제거되지 않습니다. 여전히 존재하며, 단지 숨겨져 있을 뿐입니다. 이로 인해 두 가지 실질적인 결과가 발생합니다:
파일 크기는 줄어들지 않습니다. 잘려 나간 텍스트, 이미지 및 벡터 그래픽은 PDF 데이터 스트림에 남아 있습니다. 여백을 잘라 파일 크기를 줄이는 것이 목표라면 CropBox만 설정하는 것으로는 달성할 수 없습니다.
잘린 콘텐츠는 여전히 검색할 수 있습니다. 표시되는 CropBox 밖의 텍스트는 검색 기능으로 여전히 찾을 수 있으며, 표시 영역 너머를 선택하는 방법을 아는 사용자가 복사할 수 있습니다. 이는 일반적으로 여백 자르기에는 괜찮지만, 자르기가 민감한 정보를 삭제하거나 안전하게 제거하는 방법이 아니라는 의미입니다.
콘텐츠를 진정으로 제거해야 하는 경우 — 삭제(redaction), 파일 크기 축소 또는 숨겨진 텍스트를 복구할 수 없도록 보장하기 위해 — 페이지를 다시 작성해야 합니다. 방법은 새 문서를 만들고, page.CreateTemplate()을 사용하여 잘린 페이지에서 표시되는 콘텐츠를 추출하고, 새 문서의 새 페이지에 그린 다음 결과를 저장하는 것입니다. 이렇게 하면 범위를 벗어난 콘텐츠가 파일에 더 이상 존재하지 않는 하드 자르기가 생성됩니다.
그러나 대부분의 여백 자르기 및 공백 제거 사용 사례에서는 CropBox를 사용한 소프트 자르기가 바로 원하는 것입니다: 빠르고 간단하며, 문서를 다시 작성하는 오버헤드 없이 시각적으로 깔끔한 결과를 생성합니다.
자주 묻는 질문
전체 문서 대신 단일 페이지를 자를 수 있나요?
예. CropBox는 페이지별 속성이므로 내장된 "전체 문서 자르기" 메서드는 없습니다 — 기본 예제의 루프는 모든 페이지에 동일한 여백을 적용하기 위한 편의 기능일 뿐입니다. 한 페이지만 자르려면 루프를 건너뛰고 해당 페이지에 CropBox를 직접 할당하십시오:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
자르기를 실행 취소하려면 어떻게 하나요?
CropBox를 설정하면 페이지 상자가 제자리에서 수정되며, 문서는 이전 상자를 저장하지 않습니다. page.MediaBox를 다시 page.CropBox에 할당하면 원래 보기가 복원될 것이라고 생각할 수 있지만, 의도한 대로 작동하지 않습니다 — 좌표가 현재 표시 영역의 원점을 기준으로 적용되므로 원점은 고정된 채 크기만 변경됩니다. 60포인트 자르기 후 MediaBox 크기를 다시 할당해도 표시 영역은 여전히 (60, 60)에서 시작합니다.
가장 간단한 해결책은 원본 파일이 아직 있다면 다시 로드하는 것입니다. 잘린 파일만 있는 경우 음수 오프셋을 사용하여 원점을 왼쪽 위 모서리로 되돌리고 전체 페이지 크기를 복원할 수 있습니다:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
파일이 작아지지 않았고 잘린 콘텐츠가 여전히 검색 가능한 이유는 무엇인가요?
이는 예상된 동작입니다. CropBox는 소프트 자르기를 수행합니다: 페이지의 표시 경계만 변경하며, 그 경계 밖의 콘텐츠는 파일에 남아 있어 텍스트 검색이나 복사 작업으로 여전히 찾을 수 있습니다. PDF에서 콘텐츠를 물리적으로 제거해야 하는 경우 CropBox 설정만으로는 충분하지 않습니다 — 새 문서를 만들고, page.CreateTemplate()으로 표시되는 콘텐츠를 추출하고, 새 페이지에 그린 다음 새 파일로 저장하여 페이지를 다시 작성해야 합니다.
참고 항목
Ritaglia pagine PDF: taglia margini e spazi bianchi con JavaScript

Spesso i PDF contengono più spazio bianco di quanto sia necessario — documenti scansionati con bordi spessi, disegni tecnici con margini ampi o fatture in cui conta solo la tabella centrale. Ritagliare la pagina è la soluzione naturale, ma farlo in un flusso di lavoro basato su browser non è semplice. Gli strumenti desktop compromettono l'esperienza web e l'invio del file a un server backend solleva problemi di privacy e conformità.
È qui che entra in gioco Spire.PDF for JavaScript. Funziona su WebAssembly e opera interamente all'interno del browser, caricando e salvando PDF tramite un file system virtuale (VFS) senza alcun round-trip al server. È possibile impostare a livello di codice l'area visibile di ogni pagina e consentire all'utente di scaricare il risultato ritagliato — tutto lato client. Per l'installazione e la configurazione del progetto, fare riferimento a Integra Spire.PDF for JavaScript in un progetto React. Gli esempi seguenti presuppongono che Spire.PDF sia installato e che il modulo WebAssembly sia inizializzato.
CropBox e MediaBox: spiegazione delle due caselle di pagina
Ogni pagina PDF è definita da due rettangoli, e comprendere la differenza tra loro è essenziale prima di iniziare a ritagliare.
MediaBox descrive le dimensioni fisiche della pagina — il foglio di carta completo, per così dire. È il confine più esterno e definisce lo spazio di coordinate in cui viene posizionato tutto il contenuto. Una pagina A4 standard ha un MediaBox di circa 595 × 842 punti.
CropBox definisce ciò che il visualizzatore mostra effettivamente. È una sotto-regione del MediaBox e qualsiasi contenuto che cade al di fuori del CropBox viene nascosto alla vista. Per impostazione predefinita, il CropBox corrisponde al MediaBox, ed è per questo che normalmente si vede l'intera pagina. Quando si riduce il CropBox, si sta effettivamente dicendo al lettore PDF: "Mostra solo questa porzione della pagina."
L'intuizione chiave per il ritaglio è che il CropBox deriva dal MediaBox. Si leggono le dimensioni complete della pagina da page.MediaBox.Width e page.MediaBox.Height, poi si calcola un rettangolo più piccolo — rientrato del margine desiderato su ciascun lato — e lo si assegna a page.CropBox. Le coordinate x e y del CropBox sono misurate dall'angolo in alto a sinistra della pagina, mentre width e height determinano quanto della pagina viene mantenuto.
Ritaglia tutte le pagine con un margine uniforme
Lo scenario più comune è applicare la stessa riduzione del margine a ogni pagina di un documento. Si itera su doc.Pages, si legge il MediaBox di ogni pagina e si imposta un CropBox rientrato di un numero fisso di punti su tutti e quattro i lati.
L'esempio seguente ritaglia 60 punti da ogni bordo di ogni pagina — quanto basta per rimuovere un ampio bordo bianco o una cornice indesiderata:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Entrambe le pagine vengono ritagliate con un margine di 60 punti, quindi il margine bianco e la cornice attorno alla pagina vengono rimossi:

Modifica il valore di margin per controllare quanto aggressivamente viene ritagliata la pagina. Un valore più grande rimuove più spazio bianco; un valore più piccolo esegue un ritaglio più sottile. Poiché il margine viene applicato uniformemente su tutti e quattro i lati, questo approccio funziona meglio quando il bordo indesiderato è più o meno uguale su ogni lato — cosa che di solito accade con documenti scansionati e disegni esportati.
Ritaglio di una singola pagina rispetto all'intero documento
Il ciclo nella sezione precedente applica lo stesso ritaglio a ogni pagina. Ma CropBox è una proprietà a livello di pagina — non esiste un'interfaccia di ritaglio a livello di documento. Il ciclo si limita a garantire che ogni pagina riceva lo stesso margine. Questa distinzione è importante quando le pagine hanno esigenze diverse.
Quando ritagliare l'intero documento: Usa l'approccio con ciclo quando tutte le pagine condividono lo stesso problema — ad esempio, un lotto scansionato in cui ogni pagina ha lo stesso bordo dello scanner, o un set di disegni multi-pagina esportato con margini identici. Un unico valore di margin mantiene il codice semplice e il risultato coerente.
Quando ritagliare una singola pagina: Elimina il ciclo e assegna il CropBox direttamente alla pagina di destinazione. È utile quando solo una pagina necessita di ritaglio — ad esempio, una copertina con un logo sovradimensionato, o una fattura in cui dovrebbe essere visibile solo l'area della tabella a pagina 2. Puoi anche applicare valori di ritaglio diversi a pagine diverse combinando la logica per pagina all'interno del ciclo.
Ecco come ritagliare solo la prima pagina, mantenendo un blocco di 400 × 500 punti a partire dalla posizione (80, 80) dall'angolo in alto a sinistra:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
I valori x e y specificano dove inizia la regione visibile, misurata dall'angolo in alto a sinistra della pagina. I valori width e height definiscono la dimensione di tale regione. Tutto ciò che è al di fuori di questo rettangolo viene nascosto al visualizzatore.
Ritaglio soft: cosa succede al contenuto
C'è un dettaglio importante su CropBox che è facile trascurare: esegue un ritaglio soft, non uno hard.
Quando imposti il CropBox, stai modificando il confine visibile della pagina — il rettangolo che i visualizzatori PDF mostrano e che le stampanti usano come area della pagina. Ma il contenuto che cade al di fuori di questo confine non viene rimosso dal file. È ancora lì, solo nascosto. Questo ha due conseguenze pratiche:
La dimensione del file non diminuisce. Il testo, le immagini e la grafica vettoriale ritagliati via restano nel flusso di dati PDF. Se il tuo obiettivo è ridurre la dimensione del file tagliando i margini, impostare solo il CropBox non lo raggiungerà.
Il contenuto ritagliato è ancora ricercabile. Il testo al di fuori del CropBox visibile può ancora essere trovato dalle funzioni di ricerca e copiato dagli utenti che sanno come selezionare oltre l'area visibile. Di solito va bene per tagliare i margini, ma significa che il ritaglio non è un modo per oscurare o rimuovere in modo sicuro informazioni sensibili.
Se devi eliminare davvero il contenuto — per redazione, riduzione della dimensione del file, o per garantire che il testo nascosto non possa essere recuperato — devi ricostruire la pagina. L'approccio consiste nel creare un nuovo documento, estrarre il contenuto visibile dalla pagina ritagliata usando page.CreateTemplate(), disegnarlo su una pagina nuova nel nuovo documento e salvare il risultato. Questo produce un ritaglio hard in cui il contenuto fuori dai limiti non esiste più nel file.
Per la maggior parte dei casi d'uso di taglio dei margini e rimozione dello spazio bianco, tuttavia, il ritaglio soft con CropBox è esattamente ciò che desideri: è veloce, semplice e produce un risultato visivamente pulito senza il sovraccarico di ricostruire il documento.
FAQ
Posso ritagliare una singola pagina invece dell'intero documento?
Sì. Poiché CropBox è una proprietà per pagina, non esiste un metodo integrato per "ritagliare l'intero documento" — il ciclo nell'esempio principale è solo una comodità per applicare lo stesso margine a ogni pagina. Per ritagliare solo una pagina, salta il ciclo e assegna il CropBox direttamente a quella pagina:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Come annullo un ritaglio?
Impostare CropBox modifica la casella della pagina sul posto e il documento non memorizza la casella precedente. Potresti aspettarti che assegnare page.MediaBox di nuovo a page.CropBox ripristinasse la vista originale, ma questo non funziona come previsto — le coordinate vengono applicate rispetto all'origine dell'area visibile corrente, quindi cambiano solo le dimensioni mentre l'origine resta fissa. Dopo un ritaglio di 60 punti, riassegnare le dimensioni del MediaBox lascia comunque l'area visibile che inizia da (60, 60).
La soluzione più semplice è ricaricare il file originale se lo hai ancora. Se è disponibile solo il file ritagliato, puoi spostare l'origine di nuovo nell'angolo in alto a sinistra usando offset negativi e ripristinare le dimensioni complete della pagina:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
Il file non è diventato più piccolo e il contenuto ritagliato è ancora ricercabile — perché?
Questo è il comportamento previsto. CropBox esegue un ritaglio soft: cambia solo il confine visibile della pagina, mentre il contenuto al di fuori di quel confine rimane nel file e può ancora essere trovato dalla ricerca di testo o dalle operazioni di copia. Se devi rimuovere fisicamente il contenuto dal PDF, impostare il CropBox non è sufficiente — dovresti ricostruire la pagina creando un nuovo documento, estraendo il contenuto visibile con page.CreateTemplate(), disegnandolo su una nuova pagina e salvando in un nuovo file.
Vedi anche
Rogner les pages PDF : recadrer les marges et les espaces blancs avec JavaScript

Les PDF contiennent souvent plus d'espace blanc que nécessaire — des documents numérisés aux bordures épaisses, des dessins techniques aux marges généreuses, ou des factures où seul le tableau central importe. Rogner la page est la solution naturelle, mais y parvenir dans un flux de travail basé sur le navigateur n'est pas simple. Les outils de bureau rompent l'expérience web, et l'envoi du fichier à un serveur backend soulève des préoccupations de confidentialité et de conformité.
C'est là qu'intervient Spire.PDF for JavaScript. Il s'exécute sur WebAssembly et fonctionne entièrement dans le navigateur, chargeant et enregistrant les PDF via un système de fichiers virtuel (VFS) sans aller-retour vers un serveur. Vous pouvez définir programmatiquement la zone visible de chaque page et laisser l'utilisateur télécharger le résultat rogné — le tout côté client. Pour l'installation et la configuration du projet, consultez Intégrer Spire.PDF for JavaScript dans un projet React. Les exemples ci-dessous supposent que Spire.PDF est installé et que le module WebAssembly est initialisé.
CropBox et MediaBox : deux boîtes de page expliquées
Chaque page PDF est définie par deux rectangles, et il est essentiel de comprendre leur différence avant de commencer à rogner.
MediaBox décrit les dimensions physiques de la page — la feuille de papier complète, pour ainsi dire. C'est la limite la plus externe et elle définit l'espace de coordonnées dans lequel tout le contenu est placé. Une page A4 standard possède un MediaBox d'environ 595 × 842 points.
CropBox définit ce que la visionneuse affiche réellement. C'est une sous-région du MediaBox, et tout contenu tombant en dehors du CropBox est masqué à l'affichage. Par défaut, le CropBox correspond au MediaBox, ce qui explique pourquoi vous voyez normalement la page entière. Lorsque vous réduisez le CropBox, vous dites en pratique au lecteur PDF : "Affiche uniquement cette portion de la page."
L'idée clé pour le rognage est que le CropBox est dérivé du MediaBox. Vous lisez les dimensions complètes de la page à partir de page.MediaBox.Width et page.MediaBox.Height, puis vous calculez un rectangle plus petit — réduit de la marge souhaitée de chaque côté — et vous l'affectez à page.CropBox. Les coordonnées x et y du CropBox sont mesurées depuis le coin supérieur gauche de la page, et width et height déterminent la portion de page conservée.
Rogner toutes les pages avec une marge uniforme
Le scénario le plus courant consiste à appliquer la même réduction de marge à chaque page d'un document. Vous parcourez doc.Pages, lisez le MediaBox de chaque page et définissez un CropBox réduit d'un nombre fixe de points sur les quatre côtés.
L'exemple ci-dessous retire 60 points de chaque bord de chaque page — suffisant pour supprimer une large bordure blanche ou un cadre indésirable :
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Les deux pages sont rognées avec une marge de 60 points, de sorte que la marge blanche et le cadre autour de la page sont supprimés :

Ajustez la valeur margin pour contrôler l'intensité du rognage de la page. Une valeur plus grande supprime davantage d'espace blanc ; une valeur plus petite effectue un rognage plus subtil. Comme la marge est appliquée uniformément aux quatre côtés, cette approche fonctionne mieux lorsque la bordure indésirable est à peu près égale sur chaque bord — ce qui est généralement le cas pour les documents numérisés et les dessins exportés.
Rognage d'une seule page ou de tout le document
La boucle de la section précédente applique le même rognage à chaque page. Mais CropBox est une propriété de niveau page — il n'existe pas d'interface de rognage à l'échelle du document. La boucle garantit simplement que chaque page reçoit la même marge. Cette distinction importe lorsque vos pages ont des besoins différents.
Quand rogner tout le document : utilisez l'approche par boucle lorsque toutes les pages présentent le même problème — par exemple, un lot numérisé où chaque page a la même bordure de scanner, ou un ensemble de dessins de plusieurs pages exportés avec des marges identiques. Une seule valeur margin garde le code simple et le résultat cohérent.
Quand rogner une seule page : supprimez la boucle et affectez le CropBox directement à la page cible. Cela est utile lorsqu'une seule page a besoin d'être rognée — par exemple, une page de couverture avec un logo surdimensionné, ou une facture où seule la zone du tableau de la page 2 doit être visible. Vous pouvez également appliquer des valeurs de rognage différentes à différentes pages en combinant une logique par page à l'intérieur de la boucle.
Voici comment rogner uniquement la première page, en conservant un bloc de 400 × 500 points à partir de la position (80, 80) depuis le coin supérieur gauche :
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Les valeurs x et y spécifient où commence la région visible, mesurée depuis le coin supérieur gauche de la page. Les valeurs width et height définissent la taille de cette région. Tout ce qui se trouve en dehors de ce rectangle est masqué pour la visionneuse.
Rognage doux : ce qui arrive au contenu
Un détail important concernant CropBox est facile à négliger : il effectue un rognage doux, et non un rognage définitif.
Lorsque vous définissez le CropBox, vous modifiez la limite visible de la page — le rectangle que les lecteurs PDF affichent et que les imprimantes utilisent comme zone de page. Mais le contenu qui tombe en dehors de cette limite n'est pas supprimé du fichier. Il est toujours là, simplement masqué. Cela a deux conséquences pratiques :
La taille du fichier ne diminue pas. Le texte, les images et les graphiques vectoriels rognés restent dans le flux de données du PDF. Si votre objectif est de réduire la taille du fichier en rognant les marges, définir le CropBox seul ne suffira pas.
Le contenu rogné reste recherchable. Le texte situé en dehors du CropBox visible peut toujours être trouvé par les fonctions de recherche et copié par les utilisateurs qui savent sélectionner au-delà de la zone visible. C'est généralement acceptable pour rogner les marges, mais cela signifie que le rognage n'est pas un moyen de caviarder ni de supprimer de manière sécurisée des informations sensibles.
Si vous devez véritablement éliminer du contenu — pour le caviardage, la réduction de la taille du fichier, ou pour garantir que le texte masqué ne puisse pas être récupéré — vous devez reconstruire la page. L'approche consiste à créer un nouveau document, à extraire le contenu visible de la page rognée à l'aide de page.CreateTemplate(), à le dessiner sur une nouvelle page du nouveau document, puis à enregistrer le résultat. Cela produit un rognage définitif où le contenu hors limites n'existe plus dans le fichier.
Pour la plupart des cas d'usage de rognage de marges et de suppression d'espaces blancs, toutefois, le rognage doux avec CropBox est exactement ce qu'il vous faut : il est rapide, simple et produit un résultat visuellement propre sans la surcharge liée à la reconstruction du document.
FAQ
Puis-je rogner une seule page au lieu de tout le document ?
Oui. Comme CropBox est une propriété par page, il n'existe pas de méthode intégrée pour "rogner tout le document" — la boucle de l'exemple principal n'est qu'une commodité pour appliquer la même marge à chaque page. Pour rogner une seule page, omettez la boucle et affectez le CropBox directement à cette page :
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Comment annuler un rognage ?
Définir CropBox modifie la boîte de page sur place, et le document ne conserve pas la boîte précédente. Vous pourriez penser qu'affecter page.MediaBox à page.CropBox restaurerait la vue d'origine, mais cela ne fonctionne pas comme prévu — les coordonnées sont appliquées relativement à l'origine de la zone visible actuelle, de sorte que seules les dimensions changent tandis que l'origine reste fixe. Après un rognage de 60 points, réaffecter les dimensions du MediaBox laisse toujours la zone visible commencer à (60, 60).
La solution la plus simple consiste à recharger le fichier d'origine si vous l'avez encore. Si seul le fichier rogné est disponible, vous pouvez décaler l'origine vers le coin supérieur gauche à l'aide de décalages négatifs et restaurer les dimensions complètes de la page :
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
Le fichier n'a pas diminué et le contenu rogné est toujours recherchable — pourquoi ?
Il s'agit d'un comportement attendu. CropBox effectue un rognage doux : il ne modifie que la limite visible de la page, tandis que le contenu situé en dehors de cette limite reste dans le fichier et peut toujours être trouvé par recherche de texte ou par des opérations de copie. Si vous devez supprimer physiquement le contenu du PDF, définir le CropBox ne suffit pas — vous devriez reconstruire la page en créant un nouveau document, en extrayant le contenu visible avec page.CreateTemplate(), en le dessinant sur une nouvelle page et en enregistrant le tout dans un nouveau fichier.
Voir aussi
Recortar páginas PDF: elimina márgenes y espacios en blanco con JavaScript
Tabla de contenidos

Los PDF suelen contener más espacio en blanco del que necesitan: documentos escaneados con bordes gruesos, planos de ingeniería con márgenes generosos o facturas en las que solo importa la tabla central. Recortar la página es la solución natural, pero hacerlo en un flujo de trabajo basado en el navegador no es sencillo. Las herramientas de escritorio rompen la experiencia web, y enviar el archivo a un servidor backend plantea problemas de privacidad y cumplimiento.
Aquí es donde entra en juego Spire.PDF for JavaScript. Se ejecuta sobre WebAssembly y opera por completo dentro del navegador, cargando y guardando archivos PDF a través de un sistema de archivos virtual (VFS) sin necesidad de idas y vueltas al servidor. Puede establecer el área visible de cada página mediante programación y permitir que el usuario descargue el resultado recortado, todo del lado del cliente. Para la instalación y la configuración del proyecto, consulte Integrar Spire.PDF for JavaScript en un proyecto de React. Los ejemplos siguientes suponen que Spire.PDF está instalado y que el módulo WebAssembly está inicializado.
CropBox y MediaBox: dos cuadros de página explicados
Cada página de PDF se define mediante dos rectángulos, y comprender la diferencia entre ellos es esencial antes de empezar a recortar.
MediaBox describe las dimensiones físicas de la página, es decir, la hoja de papel completa. Es el límite más externo y define el espacio de coordenadas en el que se coloca todo el contenido. Una página A4 estándar tiene un MediaBox de aproximadamente 595 × 842 puntos.
CropBox define lo que realmente muestra el visor. Es una subregión del MediaBox, y cualquier contenido que quede fuera del CropBox se oculta a la vista. De forma predeterminada, el CropBox coincide con el MediaBox, por lo que normalmente se ve la página completa. Cuando reduce el CropBox, en efecto le está diciendo al lector de PDF: "Muestre solo esta parte de la página."
La clave para el recorte es que el CropBox se deriva del MediaBox. Se leen las dimensiones completas de la página desde page.MediaBox.Width y page.MediaBox.Height, luego se calcula un rectángulo más pequeño, con un margen interior del valor que se desee en cada lado, y se asigna a page.CropBox. Las coordenadas x e y del CropBox se miden desde la esquina superior izquierda de la página, y width y height determinan cuánto de la página se conserva.
Recortar todas las páginas con un margen uniforme
El escenario más común es aplicar la misma reducción de margen a todas las páginas de un documento. Se itera sobre doc.Pages, se lee el MediaBox de cada página y se establece un CropBox con un margen interior de un número fijo de puntos en los cuatro lados.
El ejemplo siguiente recorta 60 puntos de cada borde de cada página, suficiente para eliminar un borde blanco ancho o un marco no deseado:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Ambas páginas se recortan con un margen de 60 puntos, por lo que se eliminan el margen blanco y el marco que rodea la página:

Ajuste el valor de margin para controlar con qué agresividad se recorta la página. Un valor mayor elimina más espacio en blanco; un valor menor realiza un recorte más sutil. Como el margen se aplica de forma uniforme a los cuatro lados, este enfoque funciona mejor cuando el borde no deseado es aproximadamente igual en todos los lados, que es lo habitual en documentos escaneados y planos exportados.
Recortar una sola página o todo el documento
El bucle de la sección anterior aplica el mismo recorte a todas las páginas. Pero CropBox es una propiedad de nivel de página: no existe una interfaz de recorte para todo el documento. El bucle simplemente garantiza que cada página reciba el mismo margen. Esta distinción es importante cuando sus páginas tienen necesidades diferentes.
Cuándo recortar todo el documento: utilice el enfoque con bucle cuando todas las páginas compartan el mismo problema, por ejemplo, un lote escaneado en el que cada página tiene el mismo borde del escáner, o un conjunto de planos de varias páginas exportado con márgenes idénticos. Un único valor de margin mantiene el código sencillo y el resultado coherente.
Cuándo recortar una sola página: elimine el bucle y asigne el CropBox directamente a la página de destino. Esto resulta útil cuando solo una página necesita recorte, por ejemplo, una portada con un logotipo de gran tamaño o una factura en la que solo debe verse la región de la tabla de la página 2. También puede aplicar valores de recorte distintos a páginas distintas combinando lógica por página dentro del bucle.
A continuación se muestra cómo recortar solo la primera página, conservando un bloque de 400 × 500 puntos que comienza en la posición (80, 80) desde la esquina superior izquierda:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Los valores x e y especifican dónde comienza la región visible, medidos desde la esquina superior izquierda de la página. Los valores width y height definen el tamaño de esa región. Todo lo que quede fuera de este rectángulo se oculta al visor.
Recorte suave: qué ocurre con el contenido
Hay un detalle importante sobre CropBox que es fácil pasar por alto: realiza un recorte suave, no uno duro.
Cuando establece el CropBox, cambia el límite visible de la página: el rectángulo que muestran los visores de PDF y que las impresoras utilizan como área de página. Pero el contenido que queda fuera de este límite no se elimina del archivo. Sigue estando ahí, solo que oculto. Esto tiene dos consecuencias prácticas:
El tamaño del archivo no disminuye. El texto, las imágenes y los gráficos vectoriales recortados permanecen en el flujo de datos del PDF. Si su objetivo es reducir el tamaño del archivo recortando márgenes, establecer solo el CropBox no lo conseguirá.
El contenido recortado sigue siendo buscable. El texto que está fuera del CropBox visible todavía puede encontrarse con las funciones de búsqueda y copiarse por usuarios que sepan cómo seleccionar más allá del área visible. Por lo general, esto no supone un problema al recortar márgenes, pero significa que el recorte no es una forma de censurar ni de eliminar de manera segura información confidencial.
Si necesita eliminar realmente el contenido —para censurarlo, reducir el tamaño del archivo o asegurarse de que el texto oculto no pueda recuperarse—, debe reconstruir la página. El enfoque consiste en crear un documento nuevo, extraer el contenido visible de la página recortada con page.CreateTemplate(), dibujarlo en una página nueva del nuevo documento y guardar el resultado. Esto produce un recorte duro en el que el contenido fuera de los límites ya no existe en el archivo.
No obstante, para la mayoría de los casos de uso de recorte de márgenes y eliminación de espacio en blanco, el recorte suave con CropBox es exactamente lo que se necesita: es rápido, sencillo y produce un resultado visualmente limpio sin la sobrecarga de reconstruir el documento.
Preguntas frecuentes
¿Puedo recortar una sola página en lugar de todo el documento?
Sí. Como CropBox es una propiedad por página, no hay un método integrado para "recortar todo el documento": el bucle del ejemplo principal es solo una comodidad para aplicar el mismo margen a todas las páginas. Para recortar solo una página, omita el bucle y asigne el CropBox directamente a esa página:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
¿Cómo deshago un recorte?
Establecer CropBox modifica el cuadro de página en el lugar, y el documento no almacena el cuadro anterior. Podría esperar que asignar page.MediaBox de nuevo a page.CropBox restaurara la vista original, pero esto no funciona como se pretende: las coordenadas se aplican en relación con el origen del área visible actual, por lo que solo cambian las dimensiones mientras el origen permanece fijo. Después de un recorte de 60 puntos, reasignar las dimensiones del MediaBox sigue dejando el área visible comenzando en (60, 60).
La solución más sencilla es volver a cargar el archivo original si todavía lo tiene. Si solo dispone del archivo recortado, puede desplazar el origen de nuevo a la esquina superior izquierda usando desplazamientos negativos y restaurar las dimensiones completas de la página:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
El archivo no se redujo y el contenido recortado sigue siendo buscable, ¿por qué?
Este es el comportamiento esperado. CropBox realiza un recorte suave: solo cambia el límite visible de la página, mientras que el contenido fuera de ese límite permanece en el archivo y todavía puede encontrarse mediante búsquedas de texto u operaciones de copia. Si necesita eliminar físicamente el contenido del PDF, establecer el CropBox no es suficiente: tendría que reconstruir la página creando un documento nuevo, extrayendo el contenido visible con page.CreateTemplate(), dibujándolo en una página nueva y guardando en un archivo nuevo.
Véase también
PDF-Seiten trimmen: Ränder und Leerraum mit JavaScript zuschneiden
Inhaltsverzeichnis

PDFs enthalten oft mehr Leerraum als nötig – gescannte Dokumente mit dicken Rändern, technische Zeichnungen mit großzügigen Rändern oder Rechnungen, bei denen nur die mittlere Tabelle von Bedeutung ist. Das Zuschneiden der Seite ist die naheliegende Lösung, aber in einem browserbasierten Workflow ist das nicht ohne Weiteres umsetzbar. Desktop-Tools beeinträchtigen das Web-Erlebnis, und das Senden der Datei an einen Backend-Server wirft Datenschutz- und Compliance-Bedenken auf.
Hier kommt Spire.PDF for JavaScript ins Spiel. Es läuft auf WebAssembly und arbeitet vollständig im Browser, wobei PDFs über ein virtuelles Dateisystem (VFS) geladen und gespeichert werden – ohne Server-Roundtrip. Sie können den sichtbaren Bereich jeder Seite programmatisch festlegen und den Benutzer das zugeschnittene Ergebnis herunterladen lassen – alles clientseitig. Hinweise zur Installation und Projekteinrichtung finden Sie unter Spire.PDF for JavaScript in ein React-Projekt integrieren. Die folgenden Beispiele setzen voraus, dass Spire.PDF installiert und das WebAssembly-Modul initialisiert ist.
CropBox und MediaBox: Zwei Seitenboxen erklärt
Jede PDF-Seite wird durch zwei Rechtecke definiert, und das Verständnis des Unterschieds zwischen ihnen ist unerlässlich, bevor Sie mit dem Zuschneiden beginnen.
MediaBox beschreibt die physischen Abmessungen der Seite – sozusagen das vollständige Blatt Papier. Sie ist die äußerste Begrenzung und definiert den Koordinatenraum, in dem alle Inhalte platziert werden. Eine Standard-A4-Seite hat eine MediaBox von etwa 595 × 842 Punkten.
CropBox definiert, was der Betrachter tatsächlich anzeigt. Sie ist ein Teilbereich der MediaBox, und alle Inhalte, die außerhalb der CropBox liegen, werden vor der Ansicht verborgen. Standardmäßig entspricht die CropBox der MediaBox, weshalb Sie normalerweise die gesamte Seite sehen. Wenn Sie die CropBox verkleinern, teilen Sie dem PDF-Reader im Grunde mit: "Zeigen Sie nur diesen Teil der Seite an."
Die zentrale Erkenntnis beim Zuschneiden ist, dass die CropBox von der MediaBox abgeleitet wird. Sie lesen die vollständigen Seitenabmessungen aus page.MediaBox.Width und page.MediaBox.Height, berechnen dann ein kleineres Rechteck – um den gewünschten Rand auf jeder Seite eingerückt – und weisen es page.CropBox zu. Die x- und y-Koordinaten der CropBox werden von der oberen linken Ecke der Seite aus gemessen, und width und height bestimmen, wie viel von der Seite beibehalten wird.
Alle Seiten mit einem einheitlichen Rand zuschneiden
Das häufigste Szenario ist, auf jede Seite eines Dokuments dieselbe Randreduzierung anzuwenden. Sie iterieren über doc.Pages, lesen die MediaBox jeder Seite und legen eine CropBox fest, die auf allen vier Seiten um eine feste Anzahl von Punkten eingerückt ist.
Das folgende Beispiel schneidet 60 Punkte von jedem Rand jeder Seite ab – genug, um einen breiten weißen Rahmen oder einen unerwünschten Rand zu entfernen:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Beide Seiten werden um einen Rand von 60 Punkten zugeschnitten, sodass der weiße Rand und der Rahmen um die Seite entfernt werden:

Passen Sie den Wert margin an, um zu steuern, wie stark die Seite beschnitten wird. Ein größerer Wert entfernt mehr Leerraum; ein kleinerer Wert führt einen subtileren Beschnitt durch. Da der Rand gleichmäßig auf alle vier Seiten angewendet wird, eignet sich dieser Ansatz am besten, wenn der unerwünschte Rand an jeder Kante ungefähr gleich groß ist – was bei gescannten Dokumenten und exportierten Zeichnungen typischerweise der Fall ist.
Zuschneiden einer einzelnen Seite vs. des gesamten Dokuments
Die Schleife im vorherigen Abschnitt wendet denselben Beschnitt auf jede Seite an. Aber CropBox ist eine Eigenschaft auf Seitenebene – es gibt keine dokumentsweite Zuschnitt-Schnittstelle. Die Schleife stellt lediglich sicher, dass jede Seite denselben Rand erhält. Dieser Unterschied ist wichtig, wenn Ihre Seiten unterschiedliche Anforderungen haben.
Wann das gesamte Dokument zugeschnitten werden sollte: Verwenden Sie den Schleifenansatz, wenn alle Seiten dasselbe Problem aufweisen – zum Beispiel ein gescannter Stapel, bei dem jede Seite denselben Scanner-Rand hat, oder ein mehrseitiges Zeichnungsset, das mit identischen Rändern exportiert wurde. Ein einziger margin-Wert hält den Code einfach und das Ergebnis konsistent.
Wann eine einzelne Seite zugeschnitten werden sollte: Lassen Sie die Schleife weg und weisen Sie die CropBox direkt der Zielseite zu. Das ist nützlich, wenn nur eine Seite beschnitten werden muss – zum Beispiel eine Titelseite mit einem überdimensionierten Logo oder eine Rechnung, bei der nur der Tabellenbereich auf Seite 2 sichtbar sein soll. Sie können auch unterschiedliche Zuschnittwerte auf verschiedene Seiten anwenden, indem Sie seitenspezifische Logik innerhalb der Schleife kombinieren.
So schneiden Sie nur die erste Seite zu und behalten einen 400 × 500 Punkte großen Block, der an Position (80, 80) von der oberen linken Ecke aus beginnt:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Die Werte x und y geben an, wo der sichtbare Bereich beginnt, gemessen von der oberen linken Ecke der Seite. Die Werte width und height definieren die Größe dieses Bereichs. Alles außerhalb dieses Rechtecks wird vor dem Betrachter verborgen.
Weiches Zuschneiden: Was mit dem Inhalt passiert
Es gibt ein wichtiges Detail zu CropBox, das leicht übersehen wird: Sie führt einen weichen Beschnitt durch, keinen harten.
Wenn Sie die CropBox festlegen, ändern Sie die sichtbare Begrenzung der Seite – das Rechteck, das PDF-Betrachter anzeigen und das Drucker als Seitenbereich verwenden. Aber der Inhalt, der außerhalb dieser Begrenzung liegt, wird nicht aus der Datei entfernt. Er ist weiterhin vorhanden, nur verborgen. Das hat zwei praktische Konsequenzen:
Die Dateigröße nimmt nicht ab. Der weggeschnittene Text, die Bilder und Vektorgrafiken verbleiben im PDF-Datenstrom. Wenn Ihr Ziel darin besteht, die Dateigröße durch das Beschneiden von Rändern zu reduzieren, erreichen Sie das durch das alleinige Festlegen der CropBox nicht.
Zugeschnittener Inhalt ist weiterhin durchsuchbar. Text außerhalb der sichtbaren CropBox kann weiterhin von Suchfunktionen gefunden und von Benutzern kopiert werden, die wissen, wie sie über den sichtbaren Bereich hinaus markieren. Das ist beim Beschneiden von Rändern normalerweise in Ordnung, bedeutet aber, dass Zuschneiden keine Möglichkeit ist, sensible Informationen zu schwärzen oder sicher zu entfernen.
Wenn Sie Inhalte wirklich entfernen müssen – zur Schwärzung, zur Reduzierung der Dateigröße oder um sicherzustellen, dass verborgener Text nicht wiederhergestellt werden kann –, müssen Sie die Seite neu aufbauen. Der Ansatz besteht darin, ein neues Dokument zu erstellen, den sichtbaren Inhalt mit page.CreateTemplate() aus der zugeschnittenen Seite zu extrahieren, ihn auf eine neue Seite im neuen Dokument zu zeichnen und das Ergebnis zu speichern. Dies erzeugt einen harten Beschnitt, bei dem der außerhalb liegende Inhalt nicht mehr in der Datei vorhanden ist.
Für die meisten Anwendungsfälle zum Beschneiden von Rändern und zum Entfernen von Leerraum ist jedoch das weiche Zuschneiden mit CropBox genau das Richtige: Es ist schnell, einfach und liefert ein optisch sauberes Ergebnis, ohne den Aufwand eines Neuaufbaus des Dokuments.
FAQ
Kann ich eine einzelne Seite anstelle des gesamten Dokuments zuschneiden?
Ja. Da CropBox eine Eigenschaft pro Seite ist, gibt es keine integrierte Methode zum "Zuschneiden des gesamten Dokuments" – die Schleife im Hauptbeispiel ist nur eine Bequemlichkeit, um denselben Rand auf jede Seite anzuwenden. Um nur eine Seite zuzuschneiden, überspringen Sie die Schleife und weisen Sie die CropBox direkt dieser Seite zu:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Wie mache ich einen Zuschnitt rückgängig?
Das Festlegen von CropBox ändert die Seitenbox direkt, und das Dokument speichert die vorherige Box nicht. Sie könnten erwarten, dass das Zuweisen von page.MediaBox zurück an page.CropBox die ursprüngliche Ansicht wiederherstellt, aber das funktioniert nicht wie beabsichtigt – die Koordinaten werden relativ zum Ursprung des aktuell sichtbaren Bereichs angewendet, sodass sich nur die Abmessungen ändern, während der Ursprung unverändert bleibt. Nach einem Zuschnitt um 60 Punkte beginnt der sichtbare Bereich auch nach dem erneuten Zuweisen der MediaBox-Abmessungen weiterhin bei (60, 60).
Die einfachste Lösung ist, die Originaldatei neu zu laden, wenn Sie sie noch haben. Wenn nur die zugeschnittene Datei verfügbar ist, können Sie den Ursprung mithilfe negativer Offsets zurück in die obere linke Ecke verschieben und die vollständigen Seitenabmessungen wiederherstellen:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
Die Datei wurde nicht kleiner und der zugeschnittene Inhalt ist weiterhin durchsuchbar – warum?
Dies ist das erwartete Verhalten. CropBox führt einen weichen Beschnitt durch: Sie ändert nur die sichtbare Begrenzung der Seite, während Inhalt außerhalb dieser Begrenzung in der Datei verbleibt und weiterhin durch Textsuche oder Kopiervorgänge gefunden werden kann. Wenn Sie den Inhalt physisch aus dem PDF entfernen müssen, reicht das Festlegen der CropBox nicht aus – Sie müssten die Seite neu aufbauen, indem Sie ein neues Dokument erstellen, den sichtbaren Inhalt mit page.CreateTemplate() extrahieren, ihn auf eine neue Seite zeichnen und in einer neuen Datei speichern.
Siehe auch
Обрезка страниц PDF: удаление полей и пустого пространства с помощью JavaScript
Содержание

PDF-файлы часто содержат больше пустого пространства, чем необходимо — отсканированные документы с толстыми границами, инженерные чертежи с большими полями или счета, где важна только таблица по центру. Обрезка страницы — естественное решение, но выполнить её в браузерном рабочем процессе непросто. Настольные программы нарушают работу в веб-среде, а отправка файла на серверную часть вызывает вопросы конфиденциальности и соответствия требованиям.
Здесь на помощь приходит Spire.PDF for JavaScript. Он работает на WebAssembly и полностью функционирует внутри браузера, загружая и сохраняя PDF-файлы через виртуальную файловую систему (VFS) без обращения к серверу. Вы можете программно задать видимую область каждой страницы и позволить пользователю скачать обрезанный результат — всё на стороне клиента. Информацию об установке и настройке проекта см. в разделе Интеграция Spire.PDF for JavaScript в проект React. В примерах ниже предполагается, что Spire.PDF установлен и модуль WebAssembly инициализирован.
CropBox и MediaBox: объяснение двух границ страницы
Каждая страница PDF определяется двумя прямоугольниками, и понимание разницы между ними необходимо перед началом обрезки.
MediaBox описывает физические размеры страницы — полный лист бумаги, так сказать. Это внешняя граница, и она определяет систему координат, в которой размещается всё содержимое. Стандартная страница A4 имеет MediaBox примерно 595 × 842 пункта.
CropBox определяет, что фактически отображается в просмотрщике. Это подобласть MediaBox, и любое содержимое за пределами CropBox скрыто от просмотра. По умолчанию CropBox совпадает с MediaBox, поэтому обычно видна вся страница. Когда вы уменьшаете CropBox, вы фактически сообщаете программе просмотра PDF: "Показывать только эту часть страницы."
Ключевой момент для обрезки: CropBox производен от MediaBox. Вы считываете полные размеры страницы из page.MediaBox.Width и page.MediaBox.Height, затем вычисляете меньший прямоугольник — с отступом на нужное значение с каждой стороны — и присваиваете его page.CropBox. Координаты x и y CropBox отсчитываются от верхнего левого угла страницы, а width и height определяют, какая часть страницы сохраняется.
Обрезка всех страниц с одинаковым отступом
Наиболее распространённый сценарий — применение одинакового уменьшения отступа к каждой странице документа. Вы перебираете doc.Pages, считываете MediaBox каждой страницы и задаёте CropBox с отступом на фиксированное число пунктов со всех четырёх сторон.
В приведённом ниже примере с каждого края каждой страницы срезается 60 пунктов — этого достаточно, чтобы удалить широкую белую рамку или ненужную границу:
function App() {
const cropPdfPage = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be cropped into the VFS
const inputFileName = 'ToCrop.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Trim 60 points off every side
const margin = 60;
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
// MediaBox gives the full extent of the page, from which the crop box is derived
// (x and y are measured from the top-left corner of the page)
const width = page.MediaBox.Width;
const height = page.MediaBox.Height;
page.CropBox = new pdfModule.RectangleF({
x: margin,
y: margin,
width: width - margin * 2,
height: height - margin * 2,
});
}
const outputFileName = 'CropByMargins.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Crop PDF Pages</h1>
<button onClick={cropPdfPage}>
Crop PDF
</button>
</div>
);
}
export default App;
Обе страницы обрезаны с отступом 60 пунктов, поэтому белое поле и рамка вокруг страницы удалены:

Настройте значение margin, чтобы управлять степенью обрезки страницы. Большее значение удаляет больше пустого пространства; меньшее — выполняет более тонкую обрезку. Поскольку отступ применяется единообразно ко всем четырём сторонам, этот подход лучше всего работает, когда нежелательная граница примерно одинакова по всем краям — что обычно бывает со сканированными документами и экспортированными чертежами.
Обрезка одной страницы и всего документа
Цикл в предыдущем разделе применяет одинаковую обрезку к каждой странице. Но CropBox — это свойство уровня страницы, не существует интерфейса обрезки для всего документа. Цикл просто гарантирует, что каждая страница получает одинаковый отступ. Это различие важно, когда у ваших страниц разные потребности.
Когда обрезать весь документ: Используйте подход с циклом, когда у всех страниц одна и та же проблема — например, отсканированный пакет, где каждая страница имеет одинаковую границу сканера, или многостраничный набор чертежей, экспортированный с одинаковыми полями. Единое значение margin упрощает код и делает результат согласованным.
Когда обрезать одну страницу: Уберите цикл и назначьте CropBox непосредственно целевой странице. Это полезно, когда нужно обрезать только одну страницу — например, титульную страницу с слишком большим логотипом или счёт, где должна быть видна только область таблицы на странице 2. Вы также можете применять разные значения обрезки к разным страницам, комбинируя логику для каждой страницы внутри цикла.
Вот как обрезать только первую страницу, сохранив блок размером 400 × 500 пунктов, начинающийся в позиции (80, 80) от верхнего левого угла:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Значения x и y указывают, где начинается видимая область, отсчитываясь от верхнего левого угла страницы. Значения width и height определяют размер этой области. Всё, что находится за пределами этого прямоугольника, скрыто от просмотрщика.
Мягкая обрезка: что происходит с содержимым
Есть важная деталь о CropBox, которую легко упустить: он выполняет мягкую обрезку, а не жёсткую.
Когда вы задаёте CropBox, вы меняете видимую границу страницы — прямоугольник, который отображают программы просмотра PDF и используют принтеры как область страницы. Но содержимое, выходящее за эту границу, не удаляется из файла. Оно по-прежнему там, просто скрыто. Это имеет два практических последствия:
Размер файла не уменьшается. Обрезанные текст, изображения и векторная графика остаются в потоке данных PDF. Если ваша цель — уменьшить размер файла за счёт обрезки полей, одна только установка CropBox этого не даст.
Обрезанное содержимое всё ещё доступно для поиска. Текст за пределами видимого CropBox всё ещё может быть найден функциями поиска и скопирован пользователями, которые знают, как выделять за пределами видимой области. Обычно это нормально для обрезки полей, но это означает, что обрезка не является способом редактирования или безопасного удаления конфиденциальной информации.
Если вам нужно действительно удалить содержимое — для редактирования, уменьшения размера файла или гарантии того, что скрытый текст невозможно восстановить — необходимо пересобрать страницу. Подход таков: создайте новый документ, извлеките видимое содержимое из обрезанной страницы с помощью page.CreateTemplate(), нарисуйте его на новой странице в новом документе и сохраните результат. Это даёт жёсткую обрезку, при которой содержимое за пределами границ больше не существует в файле.
Однако для большинства случаев обрезки полей и удаления пустого пространства мягкая обрезка с помощью CropBox — именно то, что нужно: она быстрая, простая и даёт визуально чистый результат без необходимости пересобирать документ.
Часто задаваемые вопросы
Можно ли обрезать одну страницу вместо всего документа?
Да. Поскольку CropBox — это свойство отдельной страницы, встроенного метода "обрезать весь документ" нет — цикл в основном примере просто удобен для применения одинакового отступа ко всем страницам. Чтобы обрезать только одну страницу, пропустите цикл и назначьте CropBox напрямую этой странице:
// Crop page 1 only: keep a 400 x 500 point block starting at (80, 80) from the top-left corner
const page = doc.Pages.get_Item(0);
page.CropBox = new pdfModule.RectangleF({ x: 80, y: 80, width: 400, height: 500 });
Как отменить обрезку?
Установка CropBox изменяет границу страницы на месте, и документ не сохраняет предыдущую границу. Можно ожидать, что присваивание page.MediaBox обратно page.CropBox восстановит исходный вид, но это не работает как задумано — координаты применяются относительно начала текущей видимой области, поэтому изменяются только размеры, а начало остаётся фиксированным. После обрезки на 60 пунктов переназначение размеров MediaBox по-прежнему оставляет видимую область начинающейся с (60, 60).
Самое простое решение — заново загрузить исходный файл, если он у вас ещё есть. Если доступен только обрезанный файл, можно сдвинуть начало обратно к верхнему левому углу с помощью отрицательных смещений и восстановить полные размеры страницы:
// Undo when the crop offset was (offsetX, offsetY)
page.CropBox = new pdfModule.RectangleF({
x: -offsetX,
y: -offsetY,
width: page.MediaBox.Width,
height: page.MediaBox.Height,
});
Файл не стал меньше, а обрезанное содержимое всё ещё доступно для поиска — почему?
Это ожидаемое поведение. CropBox выполняет мягкую обрезку: он изменяет только видимую границу страницы, тогда как содержимое за её пределами остаётся в файле и всё ещё может быть найдено текстовым поиском или скопировано. Если вам нужно физически удалить содержимое из PDF, установки CropBox недостаточно — потребуется пересобрать страницу, создав новый документ, извлекая видимое содержимое с помощью page.CreateTemplate(), рисуя его на новой странице и сохраняя в новый файл.
См. также
Contar Páginas de PDF em JavaScript: Mais do que Apenas um Número

Um único número inteiro — o total de páginas de um PDF — está por trás de um número surpreendente de decisões do mundo real: limites de upload, estimativa de papel para impressão, operações de divisão, barras de progresso. A maioria das bibliotecas de renderização de PDF apenas desenha páginas e não expõe uma contagem simples, e enviar o arquivo para um backend só para ler a contagem de páginas adiciona latência e preocupações com privacidade.
O Spire.PDF for JavaScript carrega e analisa documentos PDF diretamente no navegador por meio de WebAssembly, de modo que o arquivo nunca sai do cliente. A contagem de páginas está disponível como uma única propriedade — sem loops, sem idas e voltas ao servidor, sem soluções alternativas de renderização. Este artigo aborda como obter essa contagem e três preocupações práticas: distinguir a contagem física de páginas dos rótulos exibidos, lidar com arquivos protegidos por senha e evitar erros de off-by-one ao iterar pelas páginas.
Para instalação e configuração do projeto, consulte Integrar o Spire.PDF for JavaScript em um Projeto React. Os exemplos abaixo pressupõem que o Spire.PDF está instalado e que o módulo WebAssembly foi inicializado.
Obter a Contagem de Páginas de um Documento PDF
Depois que um objeto PdfDocument carrega um arquivo, sua propriedade Pages expõe a coleção de páginas, e a propriedade Count dessa coleção retorna o número total de páginas. Não é necessário iterar pelas páginas individualmente — a contagem fica disponível imediatamente após o carregamento.
O componente React a seguir demonstra o fluxo de trabalho completo: buscar o PDF para o sistema de arquivos virtual, criar um PdfDocument, carregar o arquivo, ler Pages.Count e gravar o resultado em um arquivo de texto para download.
function App() {
const getPageCount = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be counted into the VFS
const inputFileName = 'Multipage_Document.pdf';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Pages is the document's page collection; Count is the total page count
const pageCount = doc.Pages.Count;
// Write the result to the VFS
const outputFileName = 'PageCountResult.txt';
const report = `Document: ${inputFileName}\r\nTotal pages: ${pageCount}`;
window.dotnetRuntime.Module.FS.writeFile(outputFileName, report);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Get PDF Page Count</h1>
<button onClick={getPageCount}>
Count Pages
</button>
</div>
);
}
export default App;
O resultado é gravado em um arquivo de texto que registra o número total de páginas do documento:

Em uma aplicação de produção, você normalmente usaria o valor de pageCount diretamente em vez de gravá-lo em um arquivo — por exemplo, para validar um upload, definir o limite de um loop ou exibir metadados na interface. A abordagem de gerar um arquivo de saída mostrada aqui é útil para testes e demonstrações.
Contagem Física de Páginas vs. Rótulos de Página
Eis uma situação que pega os desenvolvedores de surpresa: você lê Pages.Count e obtém 12, mas o leitor de PDF na tela do usuário mostra a última página como "página 8". Qual número está correto?
Ambos estão — eles medem coisas diferentes. Pages.Count retorna o número de páginas físicas do documento, simplesmente. Já o número exibido por um leitor vem dos rótulos de página (a entrada /PageLabels na especificação PDF). Os rótulos de página são uma camada de apresentação que os editores usam para controlar como os números de página aparecem para o leitor. Um editor de livros pode excluir a capa da numeração, usar algarismos romanos (i, ii, iii) para o material preliminar e reiniciar o corpo do texto em 1. Depois de tudo isso, a quinta página física pode ser exibida como iii ou 1, dependendo de como os rótulos estão configurados.
Essa distinção importa quando sua aplicação precisa mostrar aos usuários um número de página que corresponda ao que eles veem em seu leitor. Se você exibir Pages.Count como a "página atual", ele não corresponderá à numeração do leitor sempre que houver rótulos de página em uso.
Quando você precisar do rótulo exibido em vez do índice físico, leia a propriedade PageLabel no objeto de página individual:
// What label the 5th physical page displays in a reader
const page = doc.Pages.get_Item(4);
console.log(page.PageLabel);
Observe o índice baseado em zero: get_Item(4) recupera a quinta página física. Quando o documento não tem rótulos de página configurados, PageLabel retorna uma string vazia. Nesse caso comum, o número exibido corresponde à ordem física das páginas, então Count é o valor que você quer.
Uma forma prática de lidar com os dois cenários é verificar PageLabel primeiro e recorrer ao índice físico quando ele estiver vazio. Isso garante que sua aplicação mostre um número de página que sempre corresponde ao que o usuário vê, independentemente de o documento usar rótulos personalizados.
Contar Páginas em um PDF Criptografado
Muitos PDFs em ambientes corporativos são protegidos por uma senha de abertura — uma medida de segurança que impede a leitura do documento sem a credencial correta. Se você tentar carregar esse arquivo com uma chamada simples de LoadFromFile, o runtime do WASM lança um erro antes mesmo de Pages.Count ser alcançado:
Can not open an encrypted document. The password is invalid.
Isso acontece no momento do carregamento, não no ponto em que você lê a contagem de páginas. O conteúdo do documento — incluindo sua estrutura de páginas — está criptografado, então a biblioteca não consegue analisá-lo sem a senha. Não há como contar páginas sem primeiro desbloquear o documento.
A solução é direta: passe a senha de abertura como segundo argumento para LoadFromFile. Depois que o documento é desbloqueado, a contagem de páginas fica disponível exatamente como em um arquivo não criptografado:
// The second argument is the open password
doc.LoadFromFile(inputFileName, 'spire123');
const pageCount = doc.Pages.Count;
Em uma aplicação real, você normalmente coletaria a senha do usuário por meio de um campo de formulário e a passaria dinamicamente, em vez de codificá-la diretamente. Se o usuário digitar a senha errada, o mesmo erro será lançado — por isso, envolver a chamada de LoadFromFile em um bloco try/catch e exibir uma mensagem amigável de "senha incorreta" é uma boa prática.
Mais uma coisa que vale destacar: essa senha é a senha de abertura (também chamada de senha de usuário), que controla quem pode visualizar o documento. Um PDF também pode ter uma senha de permissões (senha de proprietário) que restringe edição, impressão ou cópia sem bloquear a visualização. Para fins de contagem de páginas, apenas a senha de abertura é relevante — uma vez que o documento está aberto, Pages.Count funciona independentemente das restrições de permissão.
Usar a Contagem de Páginas como Limite de Loop
Depois de obter a contagem de páginas, um próximo passo natural é percorrer cada página — para extrair texto, renderizar miniaturas, dividir o documento ou aplicar alguma transformação. É aí que surge um bug sutil, mas comum: usar Count como limite superior inclusivo.
A coleção Pages é baseada em zero, o que significa que os índices válidos vão de 0 a Count - 1. Se a condição do loop for escrita com <= em vez de <, a iteração final tentará acessar a página no índice Count, que não existe. O runtime do WASM encapsula a ArgumentOutOfRangeException subjacente do .NET como um Error do JavaScript com uma mensagem como:
ArgumentOutOfRange_IndexMustBeLess Arg_ParamName_Name, index
Como a propriedade name do erro é apenas o genérico Error, você não consegue distingui-lo apenas pelo nome — é preciso comparar a string da mensagem se quiser tratá-lo especificamente.
O loop correto usa <, de modo que o último índice acessado seja Count - 1:
// The upper bound is Count - 1, so use < rather than <=
for (let i = 0; i < doc.Pages.Count; i++) {
const page = doc.Pages.get_Item(i);
}
Esse padrão de off-by-one é uma das fontes mais frequentes de erros em tempo de execução ao trabalhar com coleções de páginas. É fácil não percebê-lo nos testes se seus documentos de exemplo tiverem apenas uma ou duas páginas — o erro só aparece na iteração final, então um documento de uma única página não o acionará de forma alguma. Teste sempre a lógica do loop com um documento que tenha pelo menos três páginas para garantir que a condição de limite esteja correta.
Veja Também
- Integrar o Spire.PDF for JavaScript em um Projeto React — Guia de configuração para instalar o Spire.PDF e inicializar o módulo WebAssembly em um aplicativo React.
- Página do Produto Spire.PDF for JavaScript — Visão geral dos recursos, operações suportadas e capacidades de processamento de PDF no navegador.
- spire.pdf no npm — Página do pacote para instalar a biblioteca via npm.