Copiar e Reutilizar Páginas PDF entre Documentos com JavaScript

2026-09-28 08:36:23 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Copiar e reutilizar páginas de PDF entre documentos com JavaScript

Montar um PDF refinado a partir de arquivos de origem dispersos é uma tarefa rotineira, mas delicada: uma página de capa precisa ficar na frente de um resumo de projeto, páginas de preços pertencem ao seu contrato, um resumo trimestral reúne gráficos de uma dúzia de relatórios. Fazer isso manualmente significa lidar com vários leitores de PDF e torcer para que a ordem das páginas saia correta, com tamanhos de página incompatíveis complicando ainda mais o problema.

O Spire.PDF for JavaScript transfere toda a operação para o navegador. Com o suporte do WebAssembly, ele carrega, manipula e salva documentos PDF inteiramente no lado do cliente por meio de um sistema de arquivos virtual (VFS), o que significa que nenhum arquivo é enviado a um servidor de backend. Este artigo apresenta quatro técnicas distintas para copiar páginas de PDF entre documentos — três que realocam páginas inteiras e uma que extrai o conteúdo da página como um template reutilizável — com exemplos completos de código React para cada uma.

Para instruções de configuração do projeto e instalação, consulte Integrating Spire.PDF for JavaScript in a React Project. Os exemplos abaixo pressupõem que o Spire.PDF esteja instalado e o módulo WebAssembly tenha sido inicializado.


Quatro Maneiras de Copiar Páginas de PDF em Resumo

Antes de examinar cada método individualmente, a tabela abaixo oferece uma comparação rápida. As três primeiras técnicas movem páginas intactas e transferem automaticamente as dimensões, a rotação e as margens da página de origem. A quarta desvincula o conteúdo da geometria da página, dando a você controle total sobre o tamanho da página de destino e a posição de desenho.

Método Chamada de API O Que É Copiado Tamanho da Página Caso de Uso Típico
Inserir uma única página InsertPage Uma página em uma posição que você escolher Herdado da origem Adicionar uma capa ou página de título na frente
Inserir um intervalo de páginas InsertPageRange Um bloco consecutivo de páginas Herdado da origem Anexar uma seção específica, como tabelas de preços
Anexar um documento inteiro AppendPage Todas as páginas do documento de origem Herdado da origem Concatenar documentos completos de ponta a ponta
Desenhar o conteúdo da página como template CreateTemplate + DrawTemplate Apenas o conteúdo da página, desenhado em qualquer página Você decide o tamanho de destino Reutilizar conteúdo em tamanhos de página diferentes ou repeti-lo várias vezes

Os três primeiros métodos são simples movimentações de páginas — escolha a origem, escolha o destino, e a biblioteca faz o resto. A abordagem com template é mais avançada e abre possibilidades que a simples cópia de páginas não consegue atender, como dimensionar o conteúdo para caber em um tamanho de página diferente ou carimbar o mesmo conteúdo em várias páginas. Abordaremos primeiro os três métodos de movimentação de páginas e, em seguida, exploraremos a técnica de template em profundidade.


Copiar uma Única Página para uma Posição Específica

O mais preciso dos quatro métodos, PdfDocument.InsertPage, copia uma página de um documento de origem e a coloca em um índice exato no destino. O parâmetro resultPageIndex controla onde a cópia é inserida: passe 0 para colocá-la no início, passe a contagem atual de páginas do destino para anexá-la, ou forneça qualquer índice intermediário para inseri-la nessa posição. Omita resultPageIndex completamente e a página será colocada no final por padrão.

function App() {
  const copyPageAtPosition = 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 both the source and the target document into the VFS
    const sourceFileName = 'SourceDocument.pdf';
    const targetFileName = 'TargetDocument.pdf';
    await window.spire.FetchFileToVFS(sourceFileName, "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS(targetFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Load the two documents
    const sourceDoc = new pdfModule.PdfDocument();
    sourceDoc.LoadFromFile(sourceFileName);
    const targetDoc = new pdfModule.PdfDocument();
    targetDoc.LoadFromFile(targetFileName);

    // Copy page 1 of the source document to the front of the target document
    // pageIndex comes from the source document, resultPageIndex is where the copy lands
    targetDoc.InsertPage({ ldDoc: sourceDoc, pageIndex: 0, resultPageIndex: 0 });

    // Save the result document
    const outputFileName = 'CopyPageAtPosition.pdf';
    targetDoc.SaveToFile(outputFileName);
    sourceDoc.Close();
    targetDoc.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>Copy Page at Position</h1>
      <button onClick={copyPageAtPosition}>
        Start
      </button>
    </div>
  );
}

export default App;

Entre todos os quatro métodos de cópia, resultPageIndex é o único parâmetro que permite escolher o ponto de inserção. Defini-lo como 0 coloca a página em primeiro lugar, 1 a coloca em segundo, e passar a contagem atual de páginas do documento de destino produz o mesmo efeito que anexar.

O documento de destino cresce de duas para três páginas, com a primeira página do documento de origem agora ocupando a posição inicial:

A página 1 do documento de origem agora fica na frente do documento de destino, que passa de 2 para 3 páginas


Copiar um Intervalo de Páginas para o Final

Quando você precisa de mais de uma página, mas menos do que um documento inteiro, PdfDocument.InsertPageRange copia um bloco contíguo de páginas definido por um índice inicial e final. Diferentemente de InsertPage, este método aceita argumentos posicionais em vez de um objeto de opções, e sempre anexa as páginas copiadas ao final do destino — não há parâmetro para escolher a posição de inserção. O índice final é inclusivo, portanto passar (sourceDoc, 1, 2) copia as páginas 2 e 3 (com base zero).

function App() {
  const appendPageRange = 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 both the source and the target document into the VFS
    const sourceFileName = 'SourceDocument.pdf';
    const targetFileName = 'TargetDocument.pdf';
    await window.spire.FetchFileToVFS(sourceFileName, "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS(targetFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Load the two documents
    const sourceDoc = new pdfModule.PdfDocument();
    sourceDoc.LoadFromFile(sourceFileName);
    const targetDoc = new pdfModule.PdfDocument();
    targetDoc.LoadFromFile(targetFileName);

    // Append pages 2 to 3 of the source document to the end of the target document
    // Note: these are positional arguments, not an object; endIndex is inclusive
    targetDoc.InsertPageRange(sourceDoc, 1, 2);

    // Save the result document
    const outputFileName = 'CopyPageRange.pdf';
    targetDoc.SaveToFile(outputFileName);
    sourceDoc.Close();
    targetDoc.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>Copy Page Range</h1>
      <button onClick={appendPageRange}>
        Copy pages 2-3
      </button>
    </div>
  );
}

export default App;

O documento de destino ganha duas páginas adicionais, passando de um total de duas para quatro:

Depois que as páginas 2 e 3 do documento de origem são anexadas, o documento fica com 4 páginas


Anexar um Documento Inteiro

Para o caso mais simples — mover todas as páginas de um documento para outro — PdfDocument.AppendPage elimina a necessidade de calcular índices. Passe o objeto do documento de origem e todas as suas páginas serão anexadas ao destino em sua sequência original. Para concatenar vários documentos, chame AppendPage repetidamente com cada documento de origem, um por vez.

function App() {
  const appendWholeDocument = 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 both the source and the target document into the VFS
    const sourceFileName = 'SourceDocument.pdf';
    const targetFileName = 'TargetDocument.pdf';
    await window.spire.FetchFileToVFS(sourceFileName, "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS(targetFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Load the two documents
    const sourceDoc = new pdfModule.PdfDocument();
    sourceDoc.LoadFromFile(sourceFileName);
    const targetDoc = new pdfModule.PdfDocument();
    targetDoc.LoadFromFile(targetFileName);

    // Use AppendPage when the whole document has to be copied; all pages are appended in order
    targetDoc.AppendPage({ doc: sourceDoc });

    // Save the result document
    const outputFileName = 'CopyAllPages.pdf';
    targetDoc.SaveToFile(outputFileName);
    sourceDoc.Close();
    targetDoc.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>Copy Whole Document</h1>
      <button onClick={appendWholeDocument}>
        Start
      </button>
    </div>
  );
}

export default App;

Todas as quatro páginas do documento de origem se juntam ao destino, expandindo-o de duas para seis páginas:

Depois que todas as 4 páginas do documento de origem são anexadas, o documento fica com 6 páginas


Copiar o Conteúdo da Página com um Template

Os três métodos acima tratam uma página como uma unidade indivisível: ela se move com seu tamanho, rotação e margens preservados. Mas a montagem de documentos no mundo real frequentemente exige um controle mais refinado — colocar o conteúdo de uma página em uma página de tamanho diferente, ampliá-lo ou reduzi-lo, ou carimbar o mesmo conteúdo em várias páginas. É aqui que PdfPageBase.CreateTemplate entra em cena.

CreateTemplate extrai o conteúdo visual de uma página para um objeto PdfTemplate. Em seguida, você desenha esse template em qualquer página usando Canvas.DrawTemplate, especificando a posição e o tamanho da área de desenho. O template é desvinculado da geometria da página original, então você pode renderizá-lo em qualquer escala, em qualquer posição, em qualquer tamanho de página — e pode desenhar o mesmo template quantas vezes precisar.

Isso torna os templates especialmente úteis para cenários como:

  • Colocar o conteúdo de uma capa A5 centralizado em uma página A4 sem borda branca
  • Criar uma marca d'água ou padrão de fundo a partir de uma página existente
  • Duplicar o layout de um formulário em várias páginas novas, em escalas diferentes
function App() {
  const copyPageWithTemplate = 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 work on into the VFS
    const inputFileName = 'SourceDocument.pdf';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Load the document
    const doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // Take the page to be reused and turn it into a template: read the content once, draw it many times
    const sourcePage = doc.Pages.get_Item(0);
    const template = sourcePage.CreateTemplate();

    // First placement: insert an A4 page at position 2, a different size from the source,
    // and draw the content scaled to 297.6 x 421.6 at (80, 80)
    const page1 = doc.Pages.Insert(1, new pdfModule.SizeF(595.0, 842.0), new pdfModule.PdfMargins({ margin: 0.0 }));
    page1.Canvas.DrawTemplate(template, new pdfModule.PointF(80.0, 80.0), new pdfModule.SizeF(297.6, 421.6));

    // Second placement: insert another A4 page, drawing the same template smaller in the lower right
    const page2 = doc.Pages.Insert(2, new pdfModule.SizeF(595.0, 842.0), new pdfModule.PdfMargins({ margin: 0.0 }));
    page2.Canvas.DrawTemplate(template, new pdfModule.PointF(320.0, 460.0), new pdfModule.SizeF(200.0, 283.3));

    // Save the result document
    const outputFileName = 'CopyPageWithTemplate.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>Copy Page with Template</h1>
      <button onClick={copyPageWithTemplate}>
        Start
      </button>
    </div>
  );
}

export default App;

Alguns detalhes que vale a pena observar sobre DrawTemplate:

  • Argumento de tamanho: Quando o terceiro argumento (tamanho de destino) é omitido, o template é renderizado em suas dimensões originais, sem escala. Em uma página de destino maior, o conteúdo ocupa apenas uma parte do espaço disponível.
  • Criação de página: As dimensões e margens da página de destino vêm de Pages.Insert, não do template. No exemplo, margens zero em todos os lados fazem a origem do desenho coincidir com o canto superior esquerdo da página.
  • Múltiplos desenhos: O mesmo objeto template é desenhado duas vezes em duas páginas separadas, em posições e escalas diferentes, demonstrando a capacidade de reutilização.

O conteúdo da página 1 agora aparece em duas páginas A4 recém-inseridas, em escalas e posições diferentes, fazendo o documento crescer de quatro para seis páginas:

O conteúdo da página 1 do documento de origem é dimensionado em duas novas páginas A4, levando o documento de 4 para 6 páginas


Perguntas Frequentes

Criar uma página com new PdfMargins(0.0) gera Arg_NullReferenceException

Causa: O construtor de PdfMargins interpreta um argumento numérico simples como um identificador interno, e não como um valor de margem. Portanto, chamar new pdfModule.PdfMargins(0.0) produz um objeto que não representa margens válidas — acessar sua propriedade Left ou Top dispara Arg_NullReferenceException, e passá-lo para a criação de página produz resultados inesperados.

Solução: Sempre passe as margens como um objeto de configuração. Para margens zero uniformes, use { margin: 0.0 }; para valores individuais por lado, especifique cada lado explicitamente:

// Zero margins on all four sides
const margins = new pdfModule.PdfMargins({ margin: 0.0 });

// Or set each side separately
const custom = new pdfModule.PdfMargins({ left: 20.0, top: 20.0, right: 20.0, bottom: 20.0 });

Um erro de intervalo fora dos limites ou invertido é lançado ao copiar páginas

Causa: Os índices de página são com base zero, e endIndex em InsertPageRange é inclusivo. O intervalo válido, portanto, vai de 0 a Pages.Count - 1. Fornecer um índice fora desse intervalo gera Index out of range, enquanto definir startIndex maior que endIndex gera The start index is greater then the end index.

Solução: Proteja o limite superior limitando-o em relação a Pages.Count antes de chamar o método:

// To copy pages 2 to 4: start = 1, end = 3, with the page count as the upper bound
const start = 1;
const end = Math.min(3, sourceDoc.Pages.Count - 1);
targetDoc.InsertPageRange(sourceDoc, start, end);

Uma página rotacionada sai com a orientação errada após a cópia

Causa: CreateTemplate() captura o conteúdo desenhado da página, mas não seu ângulo de rotação (a entrada /Rotate). Quando a página de origem possui uma rotação, o sistema de coordenadas do template fica desalinhado com a página de destino — desenhá-lo diretamente coloca o conteúdo fora da área visível, e a cópia resultante tem Rotation igual a 0.

Solução: Para páginas de origem rotacionadas, prefira uma cópia de página inteira para que o ângulo de rotação acompanhe o conteúdo:

// Whole-page copy: the rotation angle comes with the page
targetDoc.InsertPage({ ldDoc: sourceDoc, pageIndex: 0, resultPageIndex: 1 });

Se a abordagem com template for inevitável, limpe temporariamente a rotação da página de origem antes de extrair o template e depois restaure o ângulo original tanto na origem quanto na nova página:

const rotation = sourcePage.Rotation.value;

// Zero it temporarily so the template exports at the page's real coordinates
sourcePage.Rotation = 0;
const newPage = doc.Pages.Insert(1, sourcePage.Size, new pdfModule.PdfMargins({ margin: 0.0 }));
newPage.Canvas.DrawTemplate(sourcePage.CreateTemplate(), new pdfModule.PointF(0.0, 0.0));

// Restore the source page and give the copy the same angle
sourcePage.Rotation = rotation;
newPage.Rotation = rotation;

Para remover a marca d'água de avaliação dos documentos de saída ou desbloquear o acesso completo aos recursos, entre em contato com vendas para obter uma licença temporária de 30 dias.


Veja Também