2008-10-20 8 views
7

Une application Web interne a été requise pour envoyer des documents à une imprimante de manière transparente. L'idée serait que l'utilisateur puisse sélectionner l'imprimante la plus proche et que l'application Web envoie ses travaux d'impression à l'imprimante sélectionnée. Canons, la première imprimante que nous devons déployer, alors mes questions sont les suivantes: Comment pourrais-je envoyer un document à imprimer sur le réseau à un Canon spécifique? Le type de Cannon est la question est un iR5570 et les documents qui seront dits seront principalement Word et PDFsEnvoi d'un document à l'imprimante avec C#

Je travaille actuellement mon chemin à travers le terrible, IE seulement le site de développement de Canon, mais j'espère que quelqu'un peut me pointer dans la bonne direction ou me diriger vers un assemblage tiers :)

Répondre

6

La phrase clé dans cette question est 'application web'.

Dans une application Web normale utilisant uniquement HTML + Javascript sur HTTP, vous ne pouvez pas envoyer un document directement à une imprimante. C'est l'une des raisons pour lesquelles les navigateurs Web existent, et sans cette fonctionnalité, l'imprimante de tout le monde recueillerait le même type de courrier indésirable qu'un télécopieur public.

Vous avez donc besoin d'une solution de rechange. Une option est de construire sur un plug-in commun, comme flash, silverlight, applet java, ou même quelque chose comme greasemonkey. Un autre est un plug-in personnalisé, comme un contrôle Winforms hébergé ou une extension de navigateur personnalisée.

Vous êtes très chanceux, car il semble que vous ayez un contrôle complet (ou une connaissance de) l'environnement de déploiement, et que cet environnement soit assez homogène. Cela signifie que vous avez une option supplémentaire que d'autres ont commencé à explorer. Si vous pouvez installer toutes les imprimantes de votre environnement sur le serveur Web, il est assez facile d'utiliser les classes d'imprimantes .Net intégrées (dans l'espace de noms System.Drawing.Printing) pour afficher ces imprimantes, ou les montrer à l'utilisateur afin qu'elles puissent Choisissez ou gardez une certaine adresse IP dans la table de correspondance des imprimantes, puis imprimez directement sur cette imprimante à partir de votre application Web. Notez que ce système peut nécessiter que votre application fonctionne avec un niveau de confiance supérieur à celui qui serait autrement requis.

Maintenant, il s'agit d'imprimer vos documents PDF et Word. Pour acrobat, vérifiez ce lien:
http://support.adobe.com/devsup/devsup.nsf/docs/52080.htm (Wayback machine)
Notez que c'est un peu daté, mais je crois que le concept est toujours valide. Vous devrez en expérimenter pour vous assurer que cela fonctionne comme prévu.

Pour Word, je ne suis généralement pas fan d'Office interop/automation dans une application web. Mais dans ce cas, vous n'éditez aucun document: il vous suffit de le charger suffisamment longtemps pour imprimer. Et le fait que vous vous fiez à une autre ressource rare (les imprimantes) devrait empêcher que cela ne se produise au-delà de ce que votre serveur Web pourrait supporter. Vous pouvez donc avoir un cas rare où l'automatisation d'Office dans un projet Web a du sens.

+0

J'ai le contrôle total de l'environnement de déploiement, c'est une application intranet interne. Office interop/autmation est horrible, et tandis que les documents sont générés par C#, nous utilisons Aspose.Words. Je peux accepter d'utiliser interop.automation pour l'impression, je vais essayer. –

+1

Si vous avez déjà Aspose, vous pouvez vérifier s'il prend en charge l'impression. –

+0

Mais tout à fait d'accord que dans 99% des cas interop bureau est horrible. –

1

La documentation PrintDocument contient un exemple détaillé d'impression à partir C#. Le nom de l'imprimante doit pointer vers une imprimante locale ou un partage d'imprimante. Voir printing-to-a-pdf-printer-programatically pour imprimer des documents PDF.

+0

Est-ce que cela ne fonctionne qu'avec le fichier txt? –

+0

Le premier exemple illustre un document texte (lignes), mais la classe PrintDocument utilise un objet Graphics pour dessiner. Cela signifie que vous pouvez utiliser la puissance des espaces de noms System.Drawing (GDI +). – gimel

+0

ah je vois .. mais je suppose que le format propriétaire (comme MS Word) n'est pas pris en charge en utilisant cette classe? –

1

Quelque chose doit traduire vos documents Word et PDF en quelque chose que l'imprimante comprend. Normalement, ce serait Word lui-même pour le premier, et une sorte de visionneuse de PDF pour le dernier. Ces programmes doivent ensuite être informés de l'imprimante à laquelle envoyer la sortie.

Une solution possible consisterait à enregistrer les documents en tant que fichiers Postscript. Ensuite, ils pourraient être envoyés à une imprimante compatible Postscript directement à partir d'une application C#. Ce serait probablement le moyen le plus facile de le faire.

6

De nombreuses imprimantes et périphériques multifonctions prennent aujourd'hui en charge l'impression directe de fichiers PDF, ce qui peut résoudre l'un de vos problèmes. Il suffit d'envoyer le fichier PDF à l'imprimante. En fait, certains supportent même l'envoi d'une URL et l'imprimante va alors chercher le document et l'imprimer. Lexmark fait cela et je pense que quelques autres fournisseurs le font aussi. Cela signifie toujours que vous devez gérer le document Word. Word 2007 prend en charge PDF (avec le add-in installed from Microsoft) et j'ai utilisé cette fonction par programme avec un grand succès en C#.

Voici le code pour que:

Microsoft.Office.Interop.Word.ApplicationClass msWord = new Microsoft.Office.Interop.Word.ApplicationClass(); 

object paramUnknown = Type.Missing; 
object missing = Type.Missing; 
object paramSaveChangesNo = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges; 
//object paramFonts = Microsoft.Office.Interop.Word.wde 
object paramFormatPDF = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatPDF; 
object paramTrue = true; 
object paramReadOnly = true; 
object sourceDoc = @"c:\input.doc"        
object target = @"c:\output.pdf"; 

msWord.Visible = false; 

//open .doc 
msWord.Documents.Open(ref sourceDoc, ref paramUnknown, ref paramReadOnly, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown); 

//so it won't show on the taskbar 
msWord.Application.Visible = false; 
msWord.WindowState = Microsoft.Office.Interop.Word.WdWindowState.wdWindowStateMinimize; 

//save .doc to new target name and format 
msWord.ActiveDocument.SaveAs(ref targetDoc, ref paramFormatPDF, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramTrue, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown); 

msWord.ActiveDocument.Close(ref missing, ref missing, ref missing); 

msWord.Quit(ref paramSaveChangesNo, ref paramUnknown, ref paramUnknown); 

Enfin, si votre appareil ne prend pas en charge l'impression de PDF, vous pouvez utiliser Ghostscript ou d'autres outils pour convertir vos PDF en PS ou même PCL. Ce n'est pas le plus grand car cela signifie exécuter un peu de code non géré ou le pire des cas, bombarder et exécuter la ligne de commande GS, cela étant dit, nous le faisons actuellement dans l'une de nos applications web et cela fonctionne bien. En aparté, nous ne le faisons pas pour l'impression mais plutôt pour la jonction d'un certain nombre de PDF, mais à la fin, cela fonctionnera de la même manière.

-1

Ce code fonctionne parfaitement Il utilise le lecteur Adobe lui-même pour imprimer

Conseils utiliser 1- ne pas oublier de fournir votre propre chemin d'installation au lecteur Adobe 2- Obtenir le nom de l'imprimante à partir des propriétés de l'imprimante vous voulez imprimer avec

utiliser la classe comme ceci:

PdfFilePrinter p = new PdfFilePrinter(); 

p.PdfFileName = @"c:\1.pdf"; 
p.Print(); 
p.PdfFileName = @"c:\2.pdf"; 
p.Print(); 

et la classe est:

public class PdfFilePrinter 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class. 
    /// </summary> 
    public PdfFilePrinter() 
    { 
     adobeReaderPath = @"C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe"; 
     printerName = "HP LaserJet P2055 Series PCL6"; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class. 
    /// </summary> 
    /// <param name="pdfFileName">Name of the PDF file.</param> 
    public PdfFilePrinter(string pdfFileName) 
    { 
     this.PdfFileName = pdfFileName; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class. 
    /// </summary> 
    /// <param name="pdfFileName">Name of the PDF file.</param> 
    /// <param name="printerName">Name of the printer.</param> 
    public PdfFilePrinter(string pdfFileName, string printerName) 
    { 
     this.pdfFileName = pdfFileName; 
     this.printerName = printerName; 
    } 

    /// <summary> 
    /// Gets or sets the name of the PDF file to print. 
    /// </summary> 
    public string PdfFileName 
    { 
     get { return this.pdfFileName; } 
     set { this.pdfFileName = value; } 
    } 
    string pdfFileName; 

    /// <summary> 
    /// Gets or sets the name of the printer. A typical name looks like '\\myserver\HP LaserJet PCL5'. 
    /// </summary> 
    /// <value>The name of the printer.</value> 
    public string PrinterName 
    { 
     get { return this.printerName; } 
     set { this.printerName = value; } 
    } 
    string printerName; 

    /// <summary> 
    /// Gets or sets the working directory. 
    /// </summary> 
    public string WorkingDirectory 
    { 
     get { return this.workingDirectory; } 
     set { this.workingDirectory = value; } 
    } 
    string workingDirectory; 

    /// <summary> 
    /// Prints the PDF file. 
    /// </summary> 
    public void Print() 
    { 
     Print(-1); 
    } 

    /// <summary> 
    /// Prints the PDF file. 
    /// </summary> 
    /// <param name="milliseconds">The number of milliseconds to wait for completing the print job.</param> 
    public void Print(int milliseconds) 
    { 
     if (this.printerName == null || this.printerName.Length == 0) 
      this.printerName = PdfFilePrinter.defaultPrinterName; 

     if (PdfFilePrinter.adobeReaderPath == null || PdfFilePrinter.adobeReaderPath.Length == 0) 
      throw new InvalidOperationException("No full qualified path to AcroRd32.exe or Acrobat.exe is set."); 

     if (this.printerName == null || this.printerName.Length == 0) 
      throw new InvalidOperationException("No printer name set."); 

     // Check whether file exists. 
     string fqName = String.Empty; 
     if (this.workingDirectory != null && this.workingDirectory.Length != 0) 
      fqName = Path.Combine(this.workingDirectory, this.pdfFileName); 
     else 
      fqName = Path.Combine(Directory.GetCurrentDirectory(), this.pdfFileName); 
     if (!File.Exists(fqName)) 
      throw new InvalidOperationException(String.Format("The file {0} does not exist.", fqName)); 

     // TODO: Check whether printer exists. 

     try 
     { 
      DoSomeVeryDirtyHacksToMakeItWork(); 

      //acrord32.exe /t   <- seems to work best 
      //acrord32.exe /h /p  <- some swear by this version 
      ProcessStartInfo startInfo = new ProcessStartInfo(); 
      startInfo.FileName = PdfFilePrinter.adobeReaderPath; 
      string args = String.Format("/t \"{0}\" \"{1}\"", this.pdfFileName, this.printerName); 
      //Debug.WriteLine(args); 
      startInfo.Arguments = args; 
      startInfo.CreateNoWindow = true; 
      startInfo.ErrorDialog = false; 
      startInfo.UseShellExecute = false; 
      if (this.workingDirectory != null && this.workingDirectory.Length != 0) 
       startInfo.WorkingDirectory = this.workingDirectory; 

      Process process = Process.Start(startInfo); 
      if (!process.WaitForExit(milliseconds)) 
      { 
       // Kill Adobe Reader/Acrobat 
       process.Kill(); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

    /// <summary> 
    /// For reasons only Adobe knows the Reader seams to open and shows the document instead of printing it 
    /// when it was not already running. 
    /// If you use PDFsharp and have any suggestions to circumvent this function, please let us know. 
    /// </summary> 
    void DoSomeVeryDirtyHacksToMakeItWork() 
    { 
     if (PdfFilePrinter.runningAcro != null) 
     { 
      if (!PdfFilePrinter.runningAcro.HasExited) 
       return; 
      PdfFilePrinter.runningAcro.Dispose(); 
      PdfFilePrinter.runningAcro = null; 
     } 
     // Is any Adobe Reader/Acrobat running? 
     Process[] processes = Process.GetProcesses(); 
     int count = processes.Length; 
     for (int idx = 0; idx < count; idx++) 
     { 
      try 
      { 
       Process process = processes[idx]; 
       ProcessModule module = process.MainModule; 

       if (String.Compare(Path.GetFileName(module.FileName), Path.GetFileName(PdfFilePrinter.adobeReaderPath), true) == 0) 
       { 
        // Yes: Fine, we can print. 
        PdfFilePrinter.runningAcro = process; 
        break; 
       } 
      } 
      catch { } 
     } 
     if (PdfFilePrinter.runningAcro == null) 
     { 
      // No: Start an Adobe Reader/Acrobat. 
      // If you are within ASP.NET, good luck... 
      PdfFilePrinter.runningAcro = Process.Start(PdfFilePrinter.adobeReaderPath); 
      PdfFilePrinter.runningAcro.WaitForInputIdle(); 
     } 
    } 
    static Process runningAcro; 

    /// <summary> 
    /// Gets or sets the Adobe Reader or Adobe Acrobat path. 
    /// A typical name looks like 'C:\Program Files\Adobe\Adobe Reader 7.0\AcroRd32.exe'. 
    /// </summary> 
    static public string AdobeReaderPath 
    { 
     get { return PdfFilePrinter.adobeReaderPath; } 
     set { PdfFilePrinter.adobeReaderPath = value; } 
    } 
    static string adobeReaderPath; 

    /// <summary> 
    /// Gets or sets the name of the default printer. A typical name looks like '\\myserver\HP LaserJet PCL5'. 
    /// </summary> 
    static public string DefaultPrinterName 
    { 
     get { return PdfFilePrinter.defaultPrinterName; } 
     set { PdfFilePrinter.defaultPrinterName = value; } 
    } 
    static string defaultPrinterName; 
} 
+0

'Ce code fonctionne parfaitement' - légèrement overoptimistic – jwg

+0

Je suis assez sûr que son travail vous pourriez contacter pour aider l'affaire au lieu de -1 –