2 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 // Jordi Mas i Hernandez, jordimash@gmail.com
28 using System.Runtime.InteropServices;
29 using System.Collections;
30 using System.Drawing.Printing;
31 using System.ComponentModel;
32 using System.Drawing.Imaging;
35 namespace System.Drawing.Printing
37 internal class PrintingServicesUnix : PrintingServices
39 private Hashtable doc_info = new Hashtable ();
40 private bool cups_installed;
42 internal PrintingServicesUnix ()
44 CheckCupsInstalled ();
47 private void CheckCupsInstalled ()
52 catch (DllNotFoundException) {
53 Console.WriteLine("libcups not found. To have printing support, you need cups installed");
54 cups_installed = false;
58 cups_installed = true;
62 internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
64 IntPtr ptr, ppd_handle;
68 if (cups_installed == false || (printer == null) || (printer == String.Empty)) {
72 ptr = cupsGetPPD (printer);
73 ppd_filename = Marshal.PtrToStringAnsi (ptr);
74 ppd_handle = ppdOpenFile (ppd_filename);
75 //Console.WriteLine ("File: {0}", ppd_filename);
77 ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
78 settings.landscape_angle = ppd.landscape;
79 settings.supports_color = (ppd.color_device == 0) ? false : true;
80 ppdClose (ppd_handle);
83 internal override void LoadPrinterResolutions (string printer, PrinterSettings settings)
85 settings.PrinterResolutions.Clear ();
86 LoadDefaultResolutions (settings.PrinterResolutions);
89 internal override void LoadPrinterPaperSizes (string printer, PrinterSettings settings)
91 IntPtr ptr, ppd_handle;
92 string ppd_filename, real_name;
96 PaperKind kind = PaperKind.Custom;
98 settings.PaperSizes.Clear ();
100 ptr = cupsGetPPD (printer);
101 ppd_filename = Marshal.PtrToStringAnsi (ptr);
102 ppd_handle = ppdOpenFile (ppd_filename);
104 ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
107 for (int i = 0; i < ppd.num_sizes; i++) {
108 size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE));
109 real_name = GetPaperSizeName (ppd, size.name);
110 ptr = new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (size));
112 w = size.width * 100 / 72;
113 h = size.length * 100 / 72;
114 ps = new PaperSize (real_name, (int) w, (int) h);
115 // TODO: Convert from name to paper kind enum
117 settings.PaperSizes.Add (ps);
120 ppdClose (ppd_handle);
123 internal override bool StartPage (GraphicsPrinter gr)
128 internal override bool EndPage (GraphicsPrinter gr)
130 GdipGetPostScriptSavePage (gr.Hdc);
134 internal override bool EndDoc (GraphicsPrinter gr)
136 DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
138 gr.Graphics.Dispose (); // Dispose object to force surface finish
139 cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, 0, IntPtr.Zero);
140 doc_info.Remove (gr.Hdc);
141 //TODO: Delete temporary file created
145 internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
147 DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
148 doc.title = doc_name;
152 internal override IntPtr CreateGraphicsContext (PrinterSettings settings)
154 IntPtr graphics = IntPtr.Zero;
155 StringBuilder name = new StringBuilder (1024);
156 int length = name.Capacity;
157 cupsTempFile (name, length);
159 GdipGetPostScriptGraphicsContext (name.ToString(),
160 settings.DefaultPageSettings.PaperSize.Width / 100 * 72,
161 settings.DefaultPageSettings.PaperSize.Height / 100 * 72,
163 300, 300, ref graphics);
165 DOCINFO doc = new DOCINFO ();
166 doc.filename = name.ToString();
167 doc.settings = settings;
168 doc_info.Add (graphics, doc);
175 internal override PrinterSettings.StringCollection InstalledPrinters {
178 IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer;
180 PrinterSettings.StringCollection col = new PrinterSettings.StringCollection (new string[] {});
182 if (cups_installed == false)
185 n_printers = cupsGetDests (ref dests);
187 ptr_printers = dests;
188 for (int i = 0; i < n_printers; i++) {
189 ptr_printer = (IntPtr) Marshal.ReadInt32 (ptr_printers);
190 str = Marshal.PtrToStringAnsi (ptr_printer);
191 Marshal.FreeHGlobal (ptr_printer);
192 ptr_printers = new IntPtr (ptr_printers.ToInt64 () + 20 /*size of CUPS_DEST*/);
195 Marshal.FreeHGlobal (dests);
200 internal override string DefaultPrinter {
204 if (cups_installed == false)
207 str = cupsGetDefault ();
208 return Marshal.PtrToStringAnsi (str);
214 private string GetPaperSizeName (PPD_FILE ppd, string name)
220 IntPtr ptr, ptr_opt, ptr_choice;
223 for (int i = 0; i < ppd.num_groups; i++) {
224 group = (PPD_GROUP) Marshal.PtrToStructure (ptr, typeof (PPD_GROUP));
225 //Console.WriteLine ("Size text:{0} name:{1} opts {2}", group.text, group.name, group.num_options);
226 ptr = new IntPtr (ptr.ToInt64 () + Marshal.SizeOf (group));
228 ptr_opt = group.options;
229 for (int n = 0; n < group.num_options; n++) {
230 option = (PPD_OPTION) Marshal.PtrToStructure (ptr_opt, typeof (PPD_OPTION));
231 ptr_opt = new IntPtr (ptr_opt.ToInt64 () + Marshal.SizeOf (option));
232 //Console.WriteLine (" key:{0} def:{1} text: {2}", option.keyword, option.defchoice, option.text);
234 if (!option.keyword.Equals ("PageSize"))
237 ptr_choice = option.choices;
238 for (int c = 0; c < option.num_choices; c++) {
239 choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr_choice, typeof (PPD_CHOICE));
240 ptr_choice = new IntPtr (ptr_choice.ToInt64 () + Marshal.SizeOf (choice));
241 //Console.WriteLine (" choice:{0} - text: {1}", choice.choice, choice.text);
242 if (name.Equals (choice.choice)) {
254 internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment)
263 [DllImport("libcups", CharSet=CharSet.Ansi)]
264 static extern int cupsGetDests (ref IntPtr dests);
266 [DllImport("libcups", CharSet=CharSet.Ansi)]
267 static extern IntPtr cupsTempFile (StringBuilder sb, int len);
269 [DllImport("libcups", CharSet=CharSet.Ansi)]
270 static extern IntPtr cupsGetDefault ();
272 [DllImport("libcups", CharSet=CharSet.Ansi)]
273 static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options);
275 [DllImport("libcups", CharSet=CharSet.Ansi)]
276 static extern IntPtr cupsGetPPD (string printer);
278 [DllImport("libcups", CharSet=CharSet.Ansi)]
279 static extern IntPtr ppdOpenFile (string filename);
281 [DllImport("libcups")]
282 static extern void ppdClose (IntPtr ppd);
284 [DllImport("libgdiplus", CharSet=CharSet.Ansi)]
285 static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
287 [DllImport("libgdiplus")]
288 static extern int GdipGetPostScriptSavePage (IntPtr graphics);
292 public struct DOCINFO
294 public PrinterSettings settings;
296 public string filename;
299 public struct PPD_SIZE
302 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
312 public struct PPD_GROUP
314 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
316 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
318 public int num_options;
319 public IntPtr options;
320 public int num_subgroups;
321 public IntPtr subgrups;
324 public struct PPD_OPTION
326 public byte conflicted;
327 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
328 public string keyword;
329 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
330 public string defchoice;
331 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
336 public int num_choices;
337 public IntPtr choices;
340 public struct PPD_CHOICE
343 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
344 public string choice;
345 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
348 public IntPtr option;
351 public struct PPD_FILE
353 public int language_level;
354 public int color_device;
355 public int variable_sizes;
356 public int accurate_screens;
357 public int contone_only;
358 public int landscape;
359 public int model_number;
360 public int manual_copies;
361 public int throughput;
362 public int colorspace;
363 public IntPtr patches;
364 public int num_emulations;
365 public IntPtr emulations;
366 public IntPtr jcl_begin;
367 public IntPtr jcl_ps;
368 public IntPtr jcl_end;
369 public IntPtr lang_encoding;
370 public IntPtr lang_version;
371 public IntPtr modelname;
372 public IntPtr ttrasterizer;
373 public IntPtr manufacturer;
374 public IntPtr product;
375 public IntPtr nickname;
376 public IntPtr shortnickname;
377 public int num_groups;
378 public IntPtr groups;
379 public int num_sizes;
382 /* There is more data after this that we are not using*/