WPF实战案例-打印

在前段时间做了一下打印,因为需要支持的格式比较多,所以wpf能打印的有限分享一下几种格式的打印(.xls .xlsx .doc .docx .png .jpg .bmp .pdf)

首先为了保证excel和word的格式问题,excel和word是调用的office进行打印的。

获取所有打印机的方法:

LocalPrintServer print = new LocalPrintServer();

                    var printers = print.GetPrintQueues();
foreach (var item in printers)
{
//打印机名称 item.Name;
}

Excel打印。三个参数 :1.打印机名称  2要打印的文件路径+名称   3要打印的sheet页名称(可以不写就打印全部sheet)

static Excel.Application Application { get; set; }
public static void PrintExcel(string printName, string fileName, List<string> sheetNames = null)
{
if (Application == null)
Application = new Excel.Application();
Application.Visible = false;
//Application.Calculation = Excel.XlCalculation.xlCalculationManual;
var book = Application.Workbooks.Open(fileName); if (sheetNames == null)
{
sheetNames = new List<string>();
Excel.Sheets sheets = book.Sheets;
for (int i = ; i <= sheets.Count; i++)
{
Excel.Worksheet workSheet = sheets.Item[i];
if (workSheet.Visible != Excel.XlSheetVisibility.xlSheetHidden)
sheetNames.Add(workSheet.Name);
}
} foreach (var item in sheetNames)
{
Excel.Worksheet workSheet = (Excel.Worksheet)book.Worksheets[item];
//------------------------打印页面相关设置--------------------------------
workSheet.PageSetup.PaperSize = Excel.XlPaperSize.xlPaperA4;//纸张大小
//workSheet.PageSetup.Orientation = Excel.XlPageOrientation.xlLandscape;//页面横向
workSheet.PageSetup.Zoom = ; //打印时页面设置,缩放比例百分之几
workSheet.PageSetup.Zoom = false; //打印时页面设置,必须设置为false,页高,页宽才有效
workSheet.PageSetup.FitToPagesWide = ; //设置页面缩放的页宽为1页宽
workSheet.PageSetup.FitToPagesTall = false; //设置页面缩放的页高自动
//workSheet.PageSetup.LeftHeader = "Nigel";//页面左上边的标志
//workSheet.PageSetup.CenterFooter = "第 &P 页,共 &N 页";//页面下标
workSheet.PageSetup.FirstPageNumber = (int)Excel.Constants.xlAutomatic;
workSheet.PageSetup.Order = Excel.XlOrder.xlDownThenOver;
workSheet.PageSetup.PrintGridlines = true; //打印单元格网线
workSheet.PageSetup.TopMargin = 1.5 / 0.035; //上边距为2cm(转换为in)
workSheet.PageSetup.BottomMargin = 1.5 / 0.035; //下边距为1.5cm
workSheet.PageSetup.LeftMargin = / 0.035; //左边距为2cm
workSheet.PageSetup.RightMargin = / 0.035; //右边距为2cm
workSheet.PageSetup.CenterHorizontally = true; //文字水平居中
//------------------------打印页面设置结束--------------------------------
workSheet.PrintOutEx(Missing.Value, Missing.Value, Missing.Value, Missing.Value, printName);
} //book.PrintOutEx(Missing.Value, Missing.Value, Missing.Value, Missing.Value, printName); //直接打印
book.Close(false); //关闭工作空间 }

excel有时候关不干净,贡献一个强制关闭的方法,可以在excel操作完成后调用:

[DllImport("User32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int Processid); public static void ExcelClose()
{
if (Application != null)
{
Application.Quit();
int iId = ;
IntPtr intptr = new IntPtr(Application.Hwnd);
System.Diagnostics.Process p = null; try
{
GetWindowThreadProcessId(intptr, out iId);
p = System.Diagnostics.Process.GetProcessById(iId); if (p != null)
{
p.Kill();
p.Dispose();
}
Application = null;
}
catch (Exception e)
{
throw e;
}
} System.GC.Collect();
}

Word打印(打印机名称,要打印的文件路径+名称)

public static void PrintWord(string printName, string fileName)
{
Word.Application appword = new Word.Application();
appword.Visible = false;
appword.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
Word.Document doc = appword.Documents.Open(fileName);
appword.ActivePrinter = printName;
doc.PrintOut(true);
doc.Close(false);
appword.Quit();
}

图片打印WPF(支持格式 png jpg bmp)

public static string PrintImage(string printName, string fileName)
{
System.Windows.Controls.PrintDialog dialog = new System.Windows.Controls.PrintDialog();//开始打印
var printers = new LocalPrintServer().GetPrintQueues(); var selectedPrinter = printers.FirstOrDefault(d => d.Name == printName);
if (selectedPrinter == null)
{
return "没有找到打印机";
}
dialog.PrintQueue = selectedPrinter;
dialog.PrintDocument(new TestDocumentPaginator(new BitmapImage(new Uri(fileName))), "Image");
return ""; }
public class TestDocumentPaginator : DocumentPaginator
{ #region 字段
private Size _pageSize;
private ImageSource image;
#endregion #region 构造
public TestDocumentPaginator(BitmapImage img)
{
image = img;
//我们使用A3纸张大小
var pageMediaSize = LocalPrintServer.GetDefaultPrintQueue()
.GetPrintCapabilities()
.PageMediaSizeCapability
.FirstOrDefault(x => x.PageMediaSizeName == PageMediaSizeName.ISOA4); if (pageMediaSize != null)
{
_pageSize = new Size((double)pageMediaSize.Width, (double)pageMediaSize.Height);
}
}
#endregion #region 重写
/// <summary>
///
/// </summary>
/// <param name="pageNumber">打印页是从0开始的</param>
/// <returns></returns>
public override DocumentPage GetPage(int pageNumber)
{
var visual = new DrawingVisual(); using (DrawingContext dc = visual.RenderOpen())
{
double imgWidth = ;
double imgHeight = ;
if (image.Height > _pageSize.Height)
{
double h = _pageSize.Height / image.Height;
imgWidth = image.Width * h;
imgHeight = image.Height * h;
}
if (image.Width > _pageSize.Width)
{
double w = _pageSize.Width / image.Width;
imgWidth = image.Width * w;
imgHeight = image.Height * w;
} if (image.Width < _pageSize.Width && image.Height < _pageSize.Height)
{
double h = _pageSize.Height / image.Height;
double w = _pageSize.Width / image.Width;
if (h > w)
{
imgWidth = image.Width * w;
imgHeight = image.Height * w;
}
else
{
imgWidth = image.Width * h;
imgHeight = image.Height * h;
} } double left = Math.Abs((_pageSize.Width - imgWidth) <= ? : (_pageSize.Width - imgWidth)) / ;
double top = Math.Abs((_pageSize.Height - imgHeight) <= ? : (_pageSize.Height - imgHeight)) / ; dc.DrawImage(image, new Rect(left, top, imgWidth, imgHeight));
} return new DocumentPage(visual, _pageSize, new Rect(_pageSize), new Rect(_pageSize));
} public override bool IsPageCountValid
{
get
{
return true;
}
} public override Size PageSize
{
get
{
return _pageSize;
}
set
{
_pageSize = value;
}
} public override IDocumentPaginatorSource Source
{
get
{
return null;
}
} public override int PageCount
{
get
{
return ;
}
}
#endregion
}
TestDocumentPaginator内部的重写方法是计算将图片全部居中显示。
关于图片打印多说一句:在之前我是使用image加载图片,然后通过PrintVisual打印控件的方式打印的,但是这种方式我发现在win7机器上打印出来的是空白纸张,还没明白是为什么,所以就用这种方式了。 PDF打印(这是调用windows api去打印,不需要乱起八糟的第三方):
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
} [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd); [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di); [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten); // SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = , dwWritten = ;
IntPtr hPrinter = new IntPtr();
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed. di.pDocName = "My C#.NET RAW Document";
di.pDataType = "RAW"; // Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, , di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
} public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr();
int nLength; nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, , pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
} public static bool SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
public static void PrintPDF(string printName, string fileName)
{
SendFileToPrinter(printName, fileName);
}

以上就是wpf常用的打印,目前看起来格式还是可以达到要求的,更多技术讨论请关注页面下方的qq群。
上一篇:使用DOM的方法获取所有li元素,然后使用jQuery()构造函数把它封装为jQuery对象


下一篇:Android图片压缩(质量压缩和尺寸压缩)