Trabalhar com operadores PDF em Java
Introdução aos operadores PDF e seu uso
Um operador é uma palavra‑chave PDF que especifica alguma ação que deve ser executada, como pintar uma forma gráfica na página. Uma palavra‑chave de operador se distingue de um objeto nomeado pela ausência de um caractere de barra inicial (2Fh). Operadores só têm significado dentro do fluxo de conteúdo.
Um fluxo de conteúdo é um objeto de fluxo PDF cujos dados consistem em instruções que descrevem os elementos gráficos a serem pintados em uma página. Mais detalhes sobre operadores PDF podem ser encontrados em the Especificação PDF.
Use esta página quando precisar de controle direto sobre um fluxo de conteúdo PDF em Java, como colocar uma imagem com matemática de matriz explícita, reutilizar o mesmo gráfico várias vezes através de um XForm ou excluir instruções de desenho de baixo nível de uma página.
Adicionar uma imagem com operadores PDF
Use operadores de baixo nível quando o posicionamento da imagem precisar ser controlado com precisão no nível do fluxo de conteúdo, em vez de através de APIs de layout de nível superior.
- Abra o PDF de origem com Document e obtenha o destino Page.
- Adicione o fluxo da imagem de entrada aos recursos da página e mantenha o nome do recurso retornado.
- Crie um Rectangle que define a área alvo e construa um Matrix dos seus limites.
- Use GSave para preservar o estado gráfico atual, ConcatenateMatrix para posicionar a imagem, Do para pintá-lo, e GRestore para restaurar o estado anterior.
- Salve o documento PDF atualizado.
public static void addImageUsingPdfOperators(Path inputFile, Path imageFile, Path outputFile) throws Exception {
try (Document document = new Document(inputFile.toString());
InputStream imageStream = Files.newInputStream(imageFile)) {
Page page = document.getPages().get_Item(1);
String imageName = page.getResources().getImages().add(imageStream);
Rectangle rectangle = new Rectangle(100, 100, 200, 200, true);
Matrix matrix = new Matrix(new double[]{
rectangle.getURX() - rectangle.getLLX(),
0,
0,
rectangle.getURY() - rectangle.getLLY(),
rectangle.getLLX(),
rectangle.getLLY()
});
page.getContents().add(new GSave());
page.getContents().add(new ConcatenateMatrix(matrix));
page.getContents().add(new Do(imageName));
page.getContents().add(new GRestore());
document.save(outputFile.toString());
}
System.out.println("Image added with PDF operators to " + outputFile);
}
Desenhar conteúdo XForm reutilizável em uma página
Use esta abordagem quando a mesma imagem ou gráfico deve ser renderizado mais de uma vez sem duplicar o recurso no arquivo PDF.
- Abra o PDF de origem com Document. obtenha o destino Page. e acesse seu OperatorCollection.
- Envolva o conteúdo da página existente com GSave e GRestore para que transformações posteriores não vazem para o fluxo de conteúdo original.
- Crie um XForm recurso, adicione a imagem aos recursos do formulário e use ConcatenateMatrix mais Do para desenhar a imagem dentro do formulário.
- Coloque o mesmo formulário em várias coordenadas de página adicionando uma matriz de translação e executando o nome do formulário com o
Dooperador. - Restaure o estado gráfico e salve o PDF de saída.
public static void drawXFormOnPage(Path inputFile, Path imageFile, Path outputFile) throws Exception {
try (Document document = new Document(inputFile.toString());
InputStream imageStream = Files.newInputStream(imageFile)) {
Page page = document.getPages().get_Item(1);
OperatorCollection pageContents = page.getContents();
pageContents.insert(1, new GSave());
pageContents.add(new GRestore());
pageContents.add(new GSave());
XForm form = XForm.createNewForm(page, document);
page.getResources().getForms().add(form);
form.getContents().add(new GSave());
form.getContents().add(new ConcatenateMatrix(200, 0, 0, 200, 0, 0));
String imageName = form.getResources().getImages().add(imageStream);
form.getContents().add(new Do(imageName));
form.getContents().add(new GRestore());
addFormAt(pageContents, form.getName(), 100, 500);
addFormAt(pageContents, form.getName(), 100, 300);
pageContents.add(new GRestore());
document.save(outputFile.toString());
}
System.out.println("XForm drawn on page in " + outputFile);
}
private static void addFormAt(OperatorCollection pageContents, String formName, double x, double y) {
pageContents.add(new GSave());
pageContents.add(new ConcatenateMatrix(1, 0, 0, 1, x, y));
pageContents.add(new Do(formName));
pageContents.add(new GRestore());
}
Remover operadores gráficos de uma página
Use este exemplo quando uma página contém operadores de desenho vetorial que devem ser removidos diretamente do fluxo de conteúdo.
- Abra o PDF de origem com Document e obtenha o destino Page.
- Itere pelos operadores de conteúdo da página e colete instâncias de Stroke, ClosePathStroke, e Fill.
- Exclua os operadores coletados do conteúdo da página e salve o PDF atualizado.
Esta técnica remove apenas as instruções de desenho direcionadas. Se a página também contiver rótulos de texto relacionados ou outros operadores não gráficos, esses itens permanecem no fluxo de conteúdo e podem precisar de uma passagem de limpeza separada.
public static void removeGraphicsObjects(Path inputFile, Path outputFile) {
try (Document document = new Document(inputFile.toString())) {
Page page = document.getPages().get_Item(1);
List<Operator> operatorsToRemove = new ArrayList<>();
for (Object item : page.getContents()) {
Operator operator = (Operator) item;
if (operator instanceof Stroke || operator instanceof ClosePathStroke || operator instanceof Fill) {
operatorsToRemove.add(operator);
}
}
page.getContents().delete(operatorsToRemove);
document.save(outputFile.toString());
}
System.out.println("Graphics operators removed in " + outputFile);
}