html或pdf在服务器端打印c#
Posted
技术标签:
【中文标题】html或pdf在服务器端打印c#【英文标题】:html or pdf printing on server side c# 【发布时间】:2012-06-26 13:18:03 【问题描述】:我知道它是许多论坛和博客中的一个已知主题。我读了很多文章。他们中的许多人都安静地提供信息。但对我来说,完成这项任务似乎需要新的方法。
我正在寻找在服务器端打印 html 的解决方案。但是在使用了许多选项后,我意识到我们
-
无法提供打印机名称或
其打印 html 原始内容,如 txt 文件
后来知道ghostscript (https://***.com/a/2600189/1238159) 可以在服务器端静默打印PDF。
还尝试使用水晶报告(但如何动态地将 HTML 内容传递给它,即使它不支持许多标签)、itextsharp、s-s-rs、pdfsharp 等,但它们都不支持许多 HTMl 标签和 W3C 标准。所以我在某一时刻结束了生成PDF。只有 wkhtmltopdf 非常适合将 html 转换为 pdf。根据我的经验,它支持每个 html 标签,这与其他任何标签都不一样。但是打印 PDf 是我多年以来的问题。
但现在即使使用 GhostScript(我使用的是 9.05 版)也面临问题。使用 localhost 我可以完美地使用它。我可以在服务器端以静默方式打印来自 UI 的任何打印机名称。但使用 IP 地址或机器名称无法正常工作。我什至实施了模拟。即使进程在调用 GhostScript 时挂起。
现在我想弄清楚的是
-
是否可以在服务器端打印 html 或 pdf(实际内容)?
任何开源工具都可以实现这一目标
我想动态传递的打印机名称
任何线索或解决方法都可能帮助全球数小时的人们。 :)
非常感谢。
问候, 帕万N
在使用了刘的建议之后。我能够在命令提示符下执行此操作(意味着 cmd.exe 在我的帐户下运行)。但我的应用程序将在网络服务下运行。 现在我遇到了一个问题ACCESS Denied
是的。最后我能够开始这个过程。并且能够使用我的域凭据在任务管理器下查看我的 gswin32c.exe 进程。代码如下:
public bool PrintVSPDF(string ghostScriptPath, int numberOfCopies, string printerName, string pdfFileName)
Logger.AddToLog("printerName", printerName);
string impersonationUsername = "";
string impersonationDomain = "";
string impersonationPWD = "";
if (ConfigurationManager.AppSettings["UName"] != null)
impersonationUsername = Encryption.Decrypt(ConfigurationManager.AppSettings["UName"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
impersonationDomain = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[0] : "";
impersonationUsername = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[1] : impersonationUsername.Split('\\')[0];
if (ConfigurationManager.AppSettings["PD"] != null)
impersonationPWD = Encryption.Decrypt(ConfigurationManager.AppSettings["PD"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
using (Impersonation imp = new Impersonation(impersonationUsername, impersonationDomain, impersonationPWD))
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = "-dPrinted -dNoCancel -dNOPAUSE -dBATCH -dNumCopies=" + Convert.ToString(numberOfCopies) + " -sDEVICE=mswinpr2 -sOutputFile=%printer%\"" + printerName + "\" \"" + pdfFileName + "\" ";
startInfo.FileName = ghostScriptPath;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
//startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UserName = impersonationUsername;
startInfo.Domain = impersonationDomain;
SecureString ss = new SecureString();
for (int i = 0; i < impersonationPWD.Length; i++)
ss.AppendChar(impersonationPWD[i]);
startInfo.Password = ss;
Process process = null;
try
process = Process.Start(startInfo);
//Logger.AddToLog("Error VS", process.StandardError.ReadToEnd());
//Logger.AddToLog("Output VS", process.StandardOutput.ReadToEnd());
//Logger.AddToLog(process.StartInfo.Arguments.ToString(), "VS Print Arguments");
//Console.WriteLine(process.StandardError.ReadToEnd() + process.StandardOutput.ReadToEnd());
//Logger.AddToLog(process.StartInfo.FileName.ToString(), "VS Print file name");
process.WaitForExit(30000);
if (process.HasExited == false)
process.Kill();
int exitcode = process.ExitCode;
process.Close();
return exitcode == 0;
catch (Exception ex)
Logger.AddToLog(ex);
return false;
但该过程在 localhost:5030 中运行良好,即在我的 Visual Studio 中运行时。但带有 IP 地址或机器名称。它只是挂起并引发此错误
adobe reader、foxit等也发生了同样的事情。
( Process must exit before requested information can be determined. : at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.get_ExitCode() )
【问题讨论】:
我对“打印服务器端”的意思感到困惑。打印机连接在哪里?您是在谈论从远程 Web 服务器向用户的本地打印机发起打印吗? “打印服务器端”表示我正在尝试在服务器端(即 IIS)打印由 XML+XSL 生成的 HTML 字符串。是的,打印机已连接到 IIS 服务器。它是一个 Intranet 应用程序。 【参考方案1】:我一直在做一个正在做这件事的项目。这是一次非常令人沮丧的经历。我发现最可靠的方法是将我的报告导出为 PDF,然后通过 Diagnostics.Process 使用 Foxit Reader(由于安全问题而不是 Adobe Reader)来打印文档。
打印机名称可以提供给 Foxit Reader 命令行参数。
我正在使用的环境是 Windows Server 2008 R2 x64 上的 IIS 7 上的 ASP.net 3.5。 我也在使用 Sql Server Reporting Services。
也许这段代码会帮助你:
public FileContentResult GetPOReport(DataTable reportData, int poNumber, string copies, out string fileName, out string downloadPath)
fileName = "PO_" + poNumber.ToString().Trim() + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".pdf";
downloadPath = "/Generated/" + fileName;
var outputFiles = new Dictionary<string, string>
"", Server.MapPath("~" + downloadPath)
;
if (!string.IsNullOrWhiteSpace(copies))
var copyList = copies.Split(new[] ',' , StringSplitOptions.RemoveEmptyEntries);
foreach (var temp in copyList)
outputFiles.Add(temp, Server.MapPath("~" + "/Generated/" + temp.Trim() + ".pdf"));
FileContentResult returnFile = null;
foreach (var outputFile in outputFiles)
var file = WriteReportToDisk(reportData, outputFile.Value, outputFile.Key);
if (file == null)
continue;
if (string.IsNullOrWhiteSpace(outputFile.Key))
returnFile = file;
else
PrintReport(outputFile.Value);
return returnFile;
public void PrintReport(string filePath)
try
if (!ConfigurationManager.AppSettings.AllKeys.Contains("AdobeReaderPath") ||
!ConfigurationManager.AppSettings.AllKeys.Contains("AdobePrintParameters") ||
!ConfigurationManager.AppSettings.AllKeys.Contains("PrinterName"))
return;
var adobeReaderPath = ConfigurationManager.AppSettings["AdobeReaderPath"].Trim();
var adobePrintParameters = ConfigurationManager.AppSettings["AdobePrintParameters"].Trim();
var printerName = ConfigurationManager.AppSettings["PrinterName"].Trim();
var printProcessDomain = ConfigurationManager.AppSettings["PrintProcessDomain"].Trim();
var printProcessUserName = ConfigurationManager.AppSettings["PrintProcessUserName"].Trim();
var printProcessPassword = ConfigurationManager.AppSettings["PrintProcessPassword"].Trim();
var userPrinter = Entities.UserPrinters.FirstOrDefault(p => p.UserName == User.Identity.Name);
if (userPrinter != null)
printerName = userPrinter.PrinterName.Trim();
using (var process = new Process
StartInfo =
new ProcessStartInfo(
adobeReaderPath,
string.Format(adobePrintParameters, filePath, printerName)
)
)
if (!string.IsNullOrWhiteSpace(printProcessUserName))
if (!string.IsNullOrWhiteSpace(printProcessDomain))
process.StartInfo.Domain = printProcessDomain;
process.StartInfo.UserName = printProcessUserName;
var securePassword = new SecureString();
foreach (var passwordCharacter in printProcessPassword)
securePassword.AppendChar(passwordCharacter);
process.StartInfo.Password = securePassword;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.LoadUserProfile = true;
process.Start();
process.WaitForExit(30000);
catch (Exception exception)
EventLog.WriteEntry("PO Suggestion Viewer", string.Format("PO Suggestion Viewer Error:\n0", exception.Message));
throw;
public FileContentResult WriteReportToDisk(DataTable reportData, string filePath, string copy)
var webReport = new WebReport()
ExportFileName = "PO Report",
ReportPath = Server.MapPath("~/Reports/PurchaseOrderReport.rdlc")
;
if (!string.IsNullOrWhiteSpace(copy))
webReport.ReportParameters.Add(new ReportParameter("Copy", copy));
if ((User != null) && (User.Identity != null) && (User.Identity.Name != null))
webReport.ReportParameters.Add(new ReportParameter("User", User.Identity.Name));
webReport.ReportDataSources.Add(new ReportDataSource("ReportData", reportData));
var report = webReport.GetReport();
Response.AddHeader("content-disposition", string.Format("attachment; filename=0.1", webReport.ExportFileName, webReport.FileNameExtension));
Response.ContentType = "application/pdf";
var file = File(report, webReport.MimeType, "POReport");
System.IO.File.WriteAllBytes(filePath, file.FileContents);
return file;
我的 web.config 包含:
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusivejavascriptEnabled" value="true" />
<add key="AdobeReaderPath" value="C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Re-ader.exe" />
<add key="AdobePrintParameters" value="-t "0" "1"" />
<add key="PrinterName" value="HP_Office" />
<add key="PrintProcessDomain" value="DOMAIN_NAME" />
<add key="PrintProcessUserName" value="DOMAIN_USER" />
<add key="PrintProcessPassword" value="DOMAIN_PASSWORD" />
</appSettings>
【讨论】:
似乎对我有帮助。我会谷歌它并找到一些与之相关的c#代码。谢谢刘。 Dusty Lau,好像我们不能发送要打印的份数。为此,我需要强加一个业务规则:)。循环可能会有所帮助。但它确实会通过假脱机和进程数量影响性能。我提到的链接是 [This(***.com/q/4868982/1238159)] 和 [This(***.com/q/7383349/1238159)] 我需要同样的东西。我让报表通过发送要生成的副本数来处理页数。 这一切似乎有点老套。但是我很惊讶地发现服务器端打印的支持很少。显然这不是经常做的事情。 是的,尘土飞扬。 Seriusly ...它的支持很少。非常感谢您的支持。并来到你的代码。我通过命令提示符尝试了 "Foxit Reader.exe" /t C:/1.pdf \\ed t-115\HP Officejet 4500 G510>> >>> 它在我的 vista 机器上什么也没做。但在win2003它的打印。我试过你的代码。猜猜假冒的一些问题。它在启动过程时给了我“拒绝访问”(就像我在 GhostScript 中遇到的一样)。在 Win2K3 中它抛出错误,但甚至没有登录我的 txt 文件。我现在一无所知。【参考方案2】:很抱歉迟到了。我教过我已经回答了这个问题。 我找到了将html转换为pdf的解决方法。 我正在使用 WKHTMLTOPDF API 将 html 转换为 pdf。与那里的许多商业产品相比,它看起来很棒。能够获得彩色/灰度、边距、索引。还有更多。
这是我关注的链接 http://code.google.com/p/wkhtmltopdf/
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"\bin\wkhtmltopdf.exe";
pdfFile = localReportPath + "\\Reports\\Savedfiles\\" + filename + ".pdf";
//Ref: http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html
startInfo.Arguments = " --minimum-font-size 16 --margin-left 10mm --margin-right 10mm --zoom 3 " + htmlFile + " " + pdfFile;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(startInfo);
p.WaitForExit();
p.Dispose();
p.Close();
同样,我发送给 ghostscript 以获得漂亮的 TIFF 文件用于传真。数据量大时性能也不错。
问候, 帕万N
【讨论】:
对我来说非常有用,甚至可以从 https 链接下载图像并包含它们...调整文档大小以适合页面宽度(其他工具如 CutePDF 打印机没有)以上是关于html或pdf在服务器端打印c#的主要内容,如果未能解决你的问题,请参考以下文章
怎么在服务器端使用Adobe reader 在线阅读PDF文件时候屏蔽掉打印、下载工具栏