Étiquette : PDF

Vincent Lecomte
[JS] Retour sur le rendu d’une page avec PDF.js

[JS] Retour sur le rendu d’une page avec PDF.js

Il y a déjà un moment nous abordions le fait de pouvoir afficher une page de PDF sous forme d’image grâce à la librairie PDF.js. Les différentes mises à jour de celle-ci ont conduit à ce que certains appels soient désormais dépréciés, bien que toujours fonctionnels.

Voici le nouveau code que nous pouvons utiliser :

pdfjsLib.getDocument(
{
	data : ao_pdfData
})
.promise.then(function(dPdf)
{
	dPdf.getPage(ai_num).then(function(page)
	{
		var canvas = document.createElement('canvas');
		canvas.id = as_id + '-page-' + ai_num;
		canvas.className = 'f-canvas';

		var vContext = canvas.getContext('2d');
		var vViewport = page.getViewport({
			scale: af_scale2,
			rotation: 0
		});
		
		canvas.height = vViewport.height;
		canvas.width = vViewport.width;

		var renderContext = {
			canvasContext: vContext,
			viewport: vViewport
		};
		
		page.cleanupAfterRender = true;
		
		var renderTask = page.render(
			renderContext
		);
		
		renderTask.promise.then(function()
		{
			if (canvas.msToBlob) 
			{
				$('#' + img_id).attr("src", 
					canvas.toDataURL(
						"image/jpeg", 0.85
					)
				);
			}
			else
			{
				canvas.toBlob(function(blob) 
				{
					let img = new Image();
					img.onload = function() { 
						URL.revokeObjectURL(img.src); 
					}; 
					img.src = URL.createObjectURL(blob);
					$('#' + img_id).attr("src", 
						img.src
					);
				}, "image/jpg", 0.85);
			}
		})
	});
});

Quelques détails concernant ce code :

  • On charge toujours le document en passant en paramètre les données qui auront été décodées à l’aide de la méthode atob(). On aura passé le contenu du PDF sous forme de chaine de caractères en Base64.
  • Petite différence : on appelle la méthode then() sur un objet “promise”. Même modification pour la tâche de rendu (variable “renderTask”).
  • La variable “viewport” est toujours initialisée avec getViewport() mais on passe un objet contenant les paramètres.
    • scale : l’échelle permettant de définir le zoom (ex: 1,5)
    • rotation : indique la rotation du document (0 = position initiale)
  • On définit toujours la hauteur et la largeur du canevas avec les valeurs du viewport.
  • On ajoute une petite option qui permet d’indiquer que la page doit être libérée et nettoyée après son rendu.
  • Petite nouveauté : l’utilisation de la méthode toBlob() dans les navigateurs qui supportent cela. Notez que si la méthode “msToBlob” existe alors on va plutôt appeler toDataUrl() pour la compatibilité avec IE.
    • On peut également déterminer le type de l’image.
    • On peut aussi indiquer la compression (ex : 0.85, 1 étant la qualité la plus élevée).

Grâce à ces modifications vous n’obtiendrez plus de message dans la console indiquant du code deprecated.

N’hésitez pas à partager votre expérience ou à suggérer des améliorations pour ce code !

[.NET] ITextSharp : lire les métadonnées d’un PDF

[.NET] ITextSharp : lire les métadonnées d’un PDF

En C# .NET, à l’aide de la librairie ITextSharp, on peut facilement lire les métadonnées d’un document. Pour rappel il s’agit d’une DLL qui permet de manipuler des documents PDF : parsing, ajout de filigranes, etc. Vous pouvez l’obtenir sur Sourceforge.

PdfReader p = new PdfReader(
	System.IO.File.ReadAllBytes("file.pdf") 
); 

string s = p.Info["CreationDate"];

A l’aide de Windev, on peut aussi effectuer un appel à ces fonctions .NET. Chargez l’assemblage dans votre projet, ensuite utilisez le code suivant. Attention : les tableaux d’objets ne sont pas pris en charge, il faudra donc utiliser une petite variante.

pclRead est un PdfReader dynamique <- allouer un PdfReader(File.ReadAllBytes(sInFile))
clInf est un Hashtable <- pclRead.Info
sTest = clInf.get_Item("CreationDate")

Et le tour est joué ! Dans notre exemple nous avons récupéré la date de création. Il est retourné sous cette forme : “D:AAAAMMJJ” suivi de l’heure. Bon développement !

[.NET] ITextSharp : IOException à l’ouverture

[.NET] ITextSharp : IOException à l’ouverture

Si vous obtenez une exception d’E/S en tenant d’ouvrir un PDF, cela peut être dû à un problème de permissions, soit au niveau de la DLL de l’assemblage, soit au niveau du fichier que l’on souhaite charger.

Cela se produit en utilisant le code suivant :

PdfReader p = new PdfReader(CHEMIN);

Le message de l’exception levée indique :

Exception Details: System.IO.IOException: 
 C:Fichier.pdf not found as file or resource.

Cela peut être causé par :

  • Un problème au niveau de la propriété “copie locale” de la référence (voir la documentation MSDN en ligne : article # t1zz5y8c)
  • Un fichier considéré comme “bloqué” par Windows : effectuez un clic droit sur le fichier, option “Propriétés” puis choisissez “Débloquer”.
  • Un problème de permissions sur le fichier. Celui-ci est peut-être stocké à un emplacement auquel l’application n’a pas accès.

On peut contourner le problème avec le code suivant.

PdfReader p = new PdfReader( 
	System.IO.File.ReadAllBytes(CHEMIN) 
);

L’erreur disparait alors.

Bon développement !

[Java] Charger et imprimer un PDF

[Java] Charger et imprimer un PDF

Comme nous l’avons vu ci-dessous, il est possible de charger et d’imprimer un document PDF grâce à la librairie PDFBox fournie par Apache. Pour rappel elle également de créer et manipuler des documents dans ce format ainsi que d’en extraire du contenu voire exporter au format image. Nous allons voir comment imprimer un ensemble de documents dont on a stocké l’emplacement dans un fichier texte.

Pour assurer le bon fonctionnement de votre application, il faudra télécharger et intégrer le package Commons Logging (actuellement en version 1.2), ainsi que les fichiers Fontbox et Jempbox si vous manipulez les polices ou si vous avez besoin du support de XMP – eXtensible Metadata Platform – (même numéro de version que l’archive PDFBox). Pour plus d’informations vous pouvez consultez la page en suivant ce lien.

Traitement des options

Notre application pourra être appelée en spécifiant deux options. La première, optionnelle, permettra de donner le nom de l’imprimante à utiliser, et la seconde constituera le nom du fichier texte qui contient tous les emplacements des PDF à imprimer, séparés par des lignes.

for (int i = 0; i < args.length; i++)
{ 
	if (args[i].equals(PRINTER_NAME)) 
	{ 
		if (i >= args.length) 
		{ 
			usage();
		} 
		
		printerName = args[i]; 
	}
	else
	{ 
		loadFile = args[i]; 
	} 
} 

if (loadFile == null)
{ 
	usage(); 
}

Dans la fonction main() on réalise une boucle simple qui analyse l’ensemble des options (arguments), qui sont en fait stockées dans le tableau de chaines “args” qui est l’unique paramètre de notre fonction principale. On s’arrête lorsqu’on a atteint la longueur maximale de ce tableau. On regarde si l’option vaut le contenu de la variable “PRINTER_NAME” (déclarée en static pour indiquer qu’elle ne fait pas partie d’une instance particulière, et final pour faire en sorte que sa valeur ne soit jamais modifiée). On l’a initialisée avec la valeur “-printerName“.

Si l’option analysée correspond bien au contenu de la fameuse variable alors il faut récupérer le paramètre qui suit. Si aucun ne suit alors on appelle la fonction usage(). En fin de boucle on regarde également si le nom du fichier texte a bien été spécifié. Si ce n’est pas le cas il faut de nouveau appeler la méthode statique usage(). Cette dernière affiche un message dans la console puis arrête l’application.

prnJob = PrinterJob.getPrinterJob();
if (printerName != null)
{
   PrintService[] prnSvc = PrinterJob.lookupPrintServices();
   boolean prnFound = false;
   for (int i = 0; !prnFound && i < prnSvc.length; i++)
   {
      if (prnSvc[i].getName().indexOf(printerName) != -1)
      {
          prnJob.setPrintService(prnService[i]);
          prnFound = true;
      }
   }
}

Déterminer l’imprimante cible

Ensuite, il faut instancier un objet de la classe PrinterJob en appelant la fonction getPrinterJob(). L’objet est alors lié à l’imprimante définie par défaut sur la machine. Attention que si aucune imprimante n’est installée alors getPrintService() renverra null, et appeler la fonction print() générera une exception. Dans notre cas on utilise la fonction lookupPrintServices() pour instancier le tableau, uniquement si un nom d’imprimante a été spécifié dans les arguments. Attention, n’oubliez pas de vérifier que le tableau n’est pas vide !

Le tableau contient donc la liste de toutes les imprimantes installées. On va donc le parcourir pour voir si l’une d’entre elle correspond au nom recherché. Le nom d’une imprimante est récupéré avec la fonction getName() de l’objet PrintService. On utilise la fonction indexOf(chaine_cherchée) pour réaliser la comparaison. Si le périphérique en question a été trouvé (printerFound == true) ou si la fin du tableau est atteinte, on peut sortir de la boucle.

try (BuffereReader br = new BufferedReader( 
	new FileReader(loadFile))) 
{ 
	line = br.readLine; 
	while (line != null) 
	{ 
		pdfFile = line; 
		File f = new File(pdfFile); 
		if (f.exists() && !f.isDirectory()) 
		{ 
			try (PDDocument doc = PDDocument.load(pdfFile)) 
			{ 
				doc.silentPrint(prnJob); 
			} 
		} 
		
		line = br.readLine(); 
	} 
}

Imprimer les documents

La dernière étape consiste à ouvrir le fichier texte et à le parcourir. On instancie donc un objet de type BufferedReader pour lire le fichier texte. Pour lire chacune des lignes, il existe la fonction readLine(). On réalise une boucle tant que la ligne lue est différente de la valeur null. Chaque ligne représente donc un emplacement de fichier PDF. On va vérifier qu’il ne s’agit pas d’un dossier et que le fichier existe (création d’un objet de File).

Si c’est le cas, on va instancier un objet PDDocument en appelant la fonction load() de la classe, qui reçoit en paramètre le nom du fichier PDF à charger. Ensuite, on appelle la fonction silentPrint() en passant en paramètre l’objet PrinterJob précédemment créé. Vous remarquerez qu’on utilise la nouvelle syntaxe de l’instruction “try” qui permet la fermeture automatique pour chaque élément ouvert (syntaxe apparue depuis la sortie de Java 7).

Une fois l’impression effectuée, on lit la ligne suivante dans notre fichier texte pour récupérer le prochain document PDF à imprimer. Pour rappel, la boucle s’arrête lorsque la fonction readLine() renvoie la valeur null.

Et après?

Imprimer des PDF par programmation est donc possible grâce à PDFBox. Mais cela peut aller plus loin puisqu’il est possible de réaliser des extractions ou de créer un nouveau document. N’hésitez pas à tester les autres fonctionnalités et à partager vos ressources. Notez que cet exemple a été adapté à partir de la source en version 1.1.0 qui est disponible sur le site DocJAR.

[Java] Bibliothèque pour manipuler des PDF

[Java] Bibliothèque pour manipuler des PDF

Pour une raison ou pour une autre vous pouvez être amenés à manipuler des PDF par programmation. De nombreux SDK sont proposés, notamment par Adobe ou même Foxit, mais ceux-ci sont plutôt couteux. Cependant il existe une alternative open-source, peut-être moins complète mais qui dépanne pourtant bien, et celle-ci est proposée par Apache. Il s’agit de la bibliothèque PDFBox.

En résumé elle permet de créer des documents PDF ou de les modifier, d’extraire le contenu de ceux-ci, de les imprimer ou bien-même de les exporter vers des fichiers image. Le projet est également disponible sous forme d’une application qui propose de nombreuses lignes de commandes, utile si ce qu’on cherche à faire reste plutôt basique (exemple : lancer l’impression d’un document sur un périphérique spécifié).

Exemple d’utilisation pour une impression (avec “pdfbox-app-1.8.9.jar”, en ligne de commande) :

java -jar "pdfbox-app-1.8.9.jar" PrintPDF -printerName "NOM_IMP" -silentPrint "NOM_FIC"

– PrintPDF : nom de la classe qui contient la fonction main().
– printerName : permet de spécifier le nom de l’imprimante cible.
– silentPrint : permet de ne pas afficher la fenêtre de sélection.

Rendez-vous sur la page officielle où vous retrouverez tous les téléchargements, ainsi qu’une documentation complète de l’API. La Javadoc complète de la dernière version (1.8.9) se trouve ici. Bon développement à toutes et à tous !