2
0

PrintingServicesUnix.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. //#define PrintDebug
  2. //
  3. // Copyright (C) 2005, 2007 Novell, Inc. http://www.novell.com
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining
  6. // a copy of this software and associated documentation files (the
  7. // "Software"), to deal in the Software without restriction, including
  8. // without limitation the rights to use, copy, modify, merge, publish,
  9. // distribute, sublicense, and/or sell copies of the Software, and to
  10. // permit persons to whom the Software is furnished to do so, subject to
  11. // the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  20. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. //
  24. // Author:
  25. //
  26. // Jordi Mas i Hernandez, [email protected]
  27. //
  28. using System.Runtime.InteropServices;
  29. using System.Collections;
  30. using System.Collections.Specialized;
  31. using System.Drawing.Printing;
  32. using System.ComponentModel;
  33. using System.Drawing.Imaging;
  34. using System.Text;
  35. using System.IO;
  36. namespace System.Drawing.Printing
  37. {
  38. internal class PrintingServicesUnix : PrintingServices
  39. {
  40. #region Private Fields
  41. private static Hashtable doc_info = new Hashtable ();
  42. private static bool cups_installed;
  43. private string printer_name;
  44. private static Hashtable installed_printers;
  45. private static string default_printer = String.Empty;
  46. #endregion
  47. #region Constructor
  48. internal PrintingServicesUnix () {
  49. }
  50. static PrintingServicesUnix () {
  51. installed_printers = new Hashtable ();
  52. CheckCupsInstalled ();
  53. }
  54. #endregion
  55. #region Properties
  56. internal static PrinterSettings.StringCollection InstalledPrinters {
  57. get {
  58. LoadPrinters();
  59. PrinterSettings.StringCollection list = new PrinterSettings.StringCollection (new string[] {});
  60. foreach (object key in installed_printers.Keys) {
  61. list.Add (key.ToString());
  62. }
  63. return list;
  64. }
  65. }
  66. internal override string DefaultPrinter {
  67. get {
  68. if (installed_printers.Count == 0)
  69. LoadPrinters();
  70. return default_printer;
  71. }
  72. }
  73. #endregion
  74. #region Methods
  75. /// <summary>
  76. /// Do a cups call to check if it is installed
  77. /// </summary>
  78. private static void CheckCupsInstalled ()
  79. {
  80. try {
  81. cupsGetDefault ();
  82. }
  83. catch (DllNotFoundException) {
  84. Console.WriteLine("libcups not found. To have printing support, you need cups installed");
  85. cups_installed = false;
  86. return;
  87. }
  88. cups_installed = true;
  89. }
  90. /// <summary>
  91. /// Open the printer's PPD file
  92. /// </summary>
  93. /// <param name="printer">Printer name, returned from cupsGetDests</param>
  94. private IntPtr OpenPrinter (string printer)
  95. {
  96. try {
  97. IntPtr ptr = cupsGetPPD (printer);
  98. string ppd_filename = Marshal.PtrToStringAnsi (ptr);
  99. IntPtr ppd_handle = ppdOpenFile (ppd_filename);
  100. return ppd_handle;
  101. }
  102. catch (Exception ex) {
  103. Console.WriteLine ("There was an error opening the printer {0}. Please check your cups installation.");
  104. #if DEBUG
  105. Console.WriteLine (ex.Message);
  106. #endif
  107. }
  108. return IntPtr.Zero;
  109. }
  110. /// <summary>
  111. /// Close the printer file
  112. /// </summary>
  113. /// <param name="handle">PPD handle</param>
  114. private void ClosePrinter (ref IntPtr handle)
  115. {
  116. try {
  117. if (handle != IntPtr.Zero)
  118. ppdClose (handle);
  119. }
  120. finally {
  121. handle = IntPtr.Zero;
  122. }
  123. }
  124. private static int OpenDests (ref IntPtr ptr) {
  125. try {
  126. return cupsGetDests (ref ptr);
  127. }
  128. catch {
  129. ptr = IntPtr.Zero;
  130. }
  131. return 0;
  132. }
  133. private static void CloseDests (ref IntPtr ptr, int count) {
  134. try {
  135. if (ptr != IntPtr.Zero)
  136. cupsFreeDests (count, ptr);
  137. }
  138. finally {
  139. ptr = IntPtr.Zero;
  140. }
  141. }
  142. /// <summary>
  143. /// Checks if a printer has a valid PPD file. Caches the result unless force is true
  144. /// </summary>
  145. /// <param name="force">Does the check disregarding the last cached value if true</param>
  146. internal override bool IsPrinterValid(string printer)
  147. {
  148. if (!cups_installed || printer == null | printer == String.Empty)
  149. return false;
  150. return installed_printers.Contains (printer);
  151. /*
  152. if (!force && this.printer_name != null && String.Intern(this.printer_name).Equals(printer))
  153. return is_printer_valid;
  154. IntPtr ptr = cupsGetPPD (printer);
  155. string ppd_filename = Marshal.PtrToStringAnsi (ptr);
  156. is_printer_valid = ppd_filename != null;
  157. this.printer_name = printer;
  158. return is_printer_valid;
  159. */
  160. }
  161. /// <summary>
  162. /// Loads the printer settings and initializes the PrinterSettings and PageSettings fields
  163. /// </summary>
  164. /// <param name="printer">Printer name</param>
  165. /// <param name="settings">PrinterSettings object to initialize</param>
  166. internal override void LoadPrinterSettings (string printer, PrinterSettings settings)
  167. {
  168. if (cups_installed == false || (printer == null) || (printer == String.Empty))
  169. return;
  170. if (installed_printers.Count == 0)
  171. LoadPrinters ();
  172. if (((SysPrn.Printer)installed_printers[printer]).Settings != null) {
  173. SysPrn.Printer p = (SysPrn.Printer) installed_printers[printer];
  174. settings.can_duplex = p.Settings.can_duplex;
  175. settings.is_plotter = p.Settings.is_plotter;
  176. settings.landscape_angle = p.Settings.landscape_angle;
  177. settings.maximum_copies = p.Settings.maximum_copies;
  178. settings.paper_sizes = p.Settings.paper_sizes;
  179. settings.paper_sources = p.Settings.paper_sources;
  180. settings.printer_capabilities = p.Settings.printer_capabilities;
  181. settings.printer_resolutions = p.Settings.printer_resolutions;
  182. settings.supports_color = p.Settings.supports_color;
  183. return;
  184. }
  185. settings.PrinterCapabilities.Clear ();
  186. IntPtr dests = IntPtr.Zero, ptr = IntPtr.Zero, ptr_printer, ppd_handle = IntPtr.Zero;
  187. string name = String.Empty;
  188. CUPS_DESTS printer_dest;
  189. PPD_FILE ppd;
  190. int ret = 0, cups_dests_size;
  191. NameValueCollection options, paper_names, paper_sources;
  192. try {
  193. ret = OpenDests (ref dests);
  194. if (ret == 0)
  195. return;
  196. cups_dests_size = Marshal.SizeOf (typeof(CUPS_DESTS));
  197. ptr = dests;
  198. for (int i = 0; i < ret; i++) {
  199. ptr_printer = (IntPtr) Marshal.ReadInt32 (ptr);
  200. if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) {
  201. name = printer;
  202. break;
  203. }
  204. ptr = (IntPtr) ((long)ptr + cups_dests_size);
  205. }
  206. if (!name.Equals(printer)) {
  207. return;
  208. }
  209. ppd_handle = OpenPrinter (printer);
  210. if (ppd_handle == IntPtr.Zero)
  211. return;
  212. printer_dest = (CUPS_DESTS) Marshal.PtrToStructure (ptr, typeof (CUPS_DESTS));
  213. options = new NameValueCollection();
  214. paper_names = new NameValueCollection();
  215. paper_sources = new NameValueCollection();
  216. LoadPrinterOptions(printer_dest.options, printer_dest.num_options, ppd_handle, options, paper_names, paper_sources);
  217. if (settings.paper_sizes == null)
  218. settings.paper_sizes = new PrinterSettings.PaperSizeCollection (new PaperSize [] {});
  219. else
  220. settings.paper_sizes.Clear();
  221. if (settings.paper_sources == null)
  222. settings.paper_sources = new PrinterSettings.PaperSourceCollection (new PaperSource [] {});
  223. else
  224. settings.paper_sources.Clear();
  225. string defsource = options["InputSlot"];
  226. string defsize = options["PageSize"];
  227. settings.DefaultPageSettings.PaperSource = LoadPrinterPaperSources (settings, defsource, paper_sources);
  228. settings.DefaultPageSettings.PaperSize = LoadPrinterPaperSizes (ppd_handle, settings, defsize, paper_names);
  229. ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
  230. settings.landscape_angle = ppd.landscape;
  231. settings.supports_color = (ppd.color_device == 0) ? false : true;
  232. settings.can_duplex = options["Duplex"] != null;
  233. ClosePrinter (ref ppd_handle);
  234. ((SysPrn.Printer)installed_printers[printer]).Settings = settings;
  235. }
  236. finally {
  237. CloseDests (ref dests, ret);
  238. }
  239. }
  240. /// <summary>
  241. /// Loads the global options of a printer plus the paper types and trays supported.
  242. /// </summary>
  243. /// <param name="options">The options field of a printer's CUPS_DESTS structure</param>
  244. /// <param name="numOptions">The number of options of the printer</param>
  245. /// <param name="ppd">A ppd handle for the printer, returned by ppdOpen</param>
  246. /// <param name="list">The list of options</param>
  247. /// <param name="paper_names">A list of types of paper (PageSize)</param>
  248. /// <param name="paper_sources">A list of trays(InputSlot) </param>
  249. private static void LoadPrinterOptions(IntPtr options, int numOptions, IntPtr ppd,
  250. NameValueCollection list,
  251. NameValueCollection paper_names,
  252. NameValueCollection paper_sources)
  253. {
  254. CUPS_OPTIONS cups_options;
  255. string option_name, option_value;
  256. int cups_size = Marshal.SizeOf(typeof(CUPS_OPTIONS));
  257. for (int j = 0; j < numOptions; j++)
  258. {
  259. cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS));
  260. option_name = Marshal.PtrToStringAnsi(cups_options.name);
  261. option_value = Marshal.PtrToStringAnsi(cups_options.val);
  262. #if PrintDebug
  263. Console.WriteLine("{0} = {1}", option_name, option_value);
  264. #endif
  265. list.Add(option_name, option_value);
  266. options = (IntPtr) ((long)options + cups_size);
  267. }
  268. LoadOptionList (ppd, "PageSize", paper_names);
  269. LoadOptionList (ppd, "InputSlot", paper_sources);
  270. }
  271. /// <summary>
  272. /// Loads the global options of a printer.
  273. /// </summary>
  274. /// <param name="options">The options field of a printer's CUPS_DESTS structure</param>
  275. /// <param name="numOptions">The number of options of the printer</param>
  276. private static NameValueCollection LoadPrinterOptions(IntPtr options, int numOptions)
  277. {
  278. CUPS_OPTIONS cups_options;
  279. string option_name, option_value;
  280. int cups_size = Marshal.SizeOf (typeof(CUPS_OPTIONS));
  281. NameValueCollection list = new NameValueCollection ();
  282. for (int j = 0; j < numOptions; j++)
  283. {
  284. cups_options = (CUPS_OPTIONS) Marshal.PtrToStructure(options, typeof(CUPS_OPTIONS));
  285. option_name = Marshal.PtrToStringAnsi (cups_options.name);
  286. option_value = Marshal.PtrToStringAnsi (cups_options.val);
  287. #if PrintDebug
  288. Console.WriteLine("{0} = {1}", option_name, option_value);
  289. #endif
  290. list.Add (option_name, option_value);
  291. options = (IntPtr) ((long)options + cups_size);
  292. }
  293. return list;
  294. }
  295. /// <summary>
  296. /// Loads a printer's options (selection of paper sizes, paper sources, etc)
  297. /// </summary>
  298. /// <param name="ppd">Printer ppd file handle</param>
  299. /// <param name="option_name">Name of the option group to load</param>
  300. /// <param name="list">List of loaded options</param>
  301. private static void LoadOptionList(IntPtr ppd, string option_name, NameValueCollection list) {
  302. IntPtr ptr = IntPtr.Zero;
  303. PPD_OPTION ppd_option;
  304. PPD_CHOICE choice;
  305. int choice_size = Marshal.SizeOf(typeof(PPD_CHOICE));
  306. ptr = ppdFindOption (ppd, option_name);
  307. if (ptr != IntPtr.Zero)
  308. {
  309. ppd_option = (PPD_OPTION) Marshal.PtrToStructure (ptr, typeof (PPD_OPTION));
  310. #if PrintDebug
  311. Console.WriteLine (" OPTION key:{0} def:{1} text: {2}", ppd_option.keyword, ppd_option.defchoice, ppd_option.text);
  312. #endif
  313. ptr = ppd_option.choices;
  314. for (int c = 0; c < ppd_option.num_choices; c++) {
  315. choice = (PPD_CHOICE) Marshal.PtrToStructure (ptr, typeof (PPD_CHOICE));
  316. list.Add(choice.choice, choice.text);
  317. #if PrintDebug
  318. Console.WriteLine (" choice:{0} - text: {1}", choice.choice, choice.text);
  319. #endif
  320. ptr = (IntPtr) ((long)ptr + choice_size);
  321. }
  322. }
  323. }
  324. /// <summary>
  325. /// Loads a printer's available resolutions
  326. /// </summary>
  327. /// <param name="printer">Printer name</param>
  328. /// <param name="settings">PrinterSettings object to fill</param>
  329. internal override void LoadPrinterResolutions (string printer, PrinterSettings settings)
  330. {
  331. settings.PrinterResolutions.Clear ();
  332. LoadDefaultResolutions (settings.PrinterResolutions);
  333. }
  334. /// <summary>
  335. /// Loads a printer's paper sizes. Returns the default PaperSize, and fills a list of paper_names for use in dialogues
  336. /// </summary>
  337. /// <param name="ppd_handle">PPD printer file handle</param>
  338. /// <param name="settings">PrinterSettings object to fill</param>
  339. /// <param name="def_size">Default paper size, from the global options of the printer</param>
  340. /// <param name="paper_names">List of available paper sizes that gets filled</param>
  341. private PaperSize LoadPrinterPaperSizes(IntPtr ppd_handle, PrinterSettings settings,
  342. string def_size, NameValueCollection paper_names)
  343. {
  344. IntPtr ptr;
  345. string real_name;
  346. PPD_FILE ppd;
  347. PPD_SIZE size;
  348. PaperSize ps;
  349. PaperSize defsize = null;
  350. ppd = (PPD_FILE) Marshal.PtrToStructure (ppd_handle, typeof (PPD_FILE));
  351. ptr = ppd.sizes;
  352. float w, h;
  353. for (int i = 0; i < ppd.num_sizes; i++) {
  354. size = (PPD_SIZE) Marshal.PtrToStructure (ptr, typeof (PPD_SIZE));
  355. real_name = paper_names[size.name];
  356. w = size.width * 100 / 72;
  357. h = size.length * 100 / 72;
  358. ps = new PaperSize (real_name, (int) w, (int) h, GetPaperKind ((int) w, (int) h), def_size == real_name);
  359. if (def_size == real_name)
  360. defsize = ps;
  361. ps.SetKind (GetPaperKind ((int) w, (int) h));
  362. settings.paper_sizes.Add (ps);
  363. ptr = (IntPtr) ((long)ptr + Marshal.SizeOf (size));
  364. }
  365. return defsize;
  366. }
  367. /// <summary>
  368. /// Loads a printer's paper sources (trays). Returns the default PaperSource, and fills a list of paper_sources for use in dialogues
  369. /// </summary>
  370. /// <param name="settings">PrinterSettings object to fill</param>
  371. /// <param name="def_source">Default paper source, from the global options of the printer</param>
  372. /// <param name="paper_sources">List of available paper sizes that gets filled</param>
  373. private PaperSource LoadPrinterPaperSources (PrinterSettings settings, string def_source,
  374. NameValueCollection paper_sources)
  375. {
  376. PaperSourceKind kind;
  377. PaperSource defsource = null;
  378. foreach(string source in paper_sources) {
  379. switch (source)
  380. {
  381. case "Tray":
  382. kind = PaperSourceKind.AutomaticFeed;
  383. break;
  384. case "Envelope":
  385. kind = PaperSourceKind.Envelope;
  386. break;
  387. case "Manual":
  388. kind = PaperSourceKind.Manual;
  389. break;
  390. default:
  391. kind = PaperSourceKind.Custom;
  392. break;
  393. }
  394. settings.paper_sources.Add (new PaperSource (paper_sources[source], kind, def_source == source));
  395. if (def_source == source)
  396. defsource = settings.paper_sources[settings.paper_sources.Count-1];
  397. }
  398. if (defsource == null && settings.paper_sources.Count > 0)
  399. return settings.paper_sources[0];
  400. return defsource;
  401. }
  402. /// <summary>
  403. /// </summary>
  404. /// <param name="load"></param>
  405. /// <param name="def_printer"></param>
  406. private static void LoadPrinters()
  407. {
  408. installed_printers.Clear ();
  409. if (cups_installed == false)
  410. return;
  411. IntPtr dests = IntPtr.Zero, ptr_printers;
  412. CUPS_DESTS printer;
  413. int n_printers = 0;
  414. int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS));
  415. string name, first, type, status, comment;
  416. first = type = status = comment = String.Empty;
  417. int state = 0;
  418. try {
  419. n_printers = OpenDests (ref dests);
  420. ptr_printers = dests;
  421. for (int i = 0; i < n_printers; i++) {
  422. printer = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
  423. name = Marshal.PtrToStringAnsi (printer.name);
  424. if (printer.is_default == 1)
  425. default_printer = name;
  426. if (first.Equals (String.Empty))
  427. first = name;
  428. NameValueCollection options = LoadPrinterOptions(printer.options, printer.num_options);
  429. if (options["printer-state"] != null)
  430. state = Int32.Parse(options["printer-state"]);
  431. if (options["printer-comment"] != null)
  432. comment = options["printer-state"];
  433. switch(state) {
  434. case 4:
  435. status = "Printing";
  436. break;
  437. case 5:
  438. status = "Stopped";
  439. break;
  440. default:
  441. status = "Ready";
  442. break;
  443. }
  444. installed_printers.Add (name, new SysPrn.Printer (String.Empty, type, status, comment));
  445. ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size);
  446. }
  447. }
  448. finally {
  449. CloseDests (ref dests, n_printers);
  450. }
  451. if (default_printer.Equals (String.Empty))
  452. default_printer = first;
  453. }
  454. /// <summary>
  455. /// Gets a printer's settings for use in the print dialogue
  456. /// </summary>
  457. /// <param name="printer"></param>
  458. /// <param name="port"></param>
  459. /// <param name="type"></param>
  460. /// <param name="status"></param>
  461. /// <param name="comment"></param>
  462. internal override void GetPrintDialogInfo (string printer, ref string port, ref string type, ref string status, ref string comment) {
  463. int count = 0, state = -1;
  464. bool found = false;
  465. CUPS_DESTS cups_dests;
  466. IntPtr dests = IntPtr.Zero, ptr_printers, ptr_printer;
  467. int cups_dests_size = Marshal.SizeOf(typeof(CUPS_DESTS));
  468. if (cups_installed == false)
  469. return;
  470. try {
  471. count = OpenDests (ref dests);
  472. if (count == 0)
  473. return;
  474. ptr_printers = dests;
  475. for (int i = 0; i < count; i++) {
  476. ptr_printer = (IntPtr) Marshal.ReadInt32 (ptr_printers);
  477. if (Marshal.PtrToStringAnsi (ptr_printer).Equals(printer)) {
  478. found = true;
  479. break;
  480. }
  481. ptr_printers = (IntPtr) ((long)ptr_printers + cups_dests_size);
  482. }
  483. if (!found)
  484. return;
  485. cups_dests = (CUPS_DESTS) Marshal.PtrToStructure (ptr_printers, typeof (CUPS_DESTS));
  486. NameValueCollection options = LoadPrinterOptions(cups_dests.options, cups_dests.num_options);
  487. if (options["printer-state"] != null)
  488. state = Int32.Parse(options["printer-state"]);
  489. if (options["printer-comment"] != null)
  490. comment = options["printer-state"];
  491. switch(state) {
  492. case 4:
  493. status = "Printing";
  494. break;
  495. case 5:
  496. status = "Stopped";
  497. break;
  498. default:
  499. status = "Ready";
  500. break;
  501. }
  502. }
  503. finally {
  504. CloseDests (ref dests, count);
  505. }
  506. }
  507. /// <summary>
  508. /// Returns the appropriate PaperKind for the width and height
  509. /// </summary>
  510. /// <param name="width"></param>
  511. /// <param name="height"></param>
  512. private PaperKind GetPaperKind (int width, int height)
  513. {
  514. if (width == 827 && height == 1169)
  515. return PaperKind.A4;
  516. if (width == 583 && height == 827)
  517. return PaperKind.A5;
  518. if (width == 717 && height == 1012)
  519. return PaperKind.B5;
  520. if (width == 693 && height == 984)
  521. return PaperKind.B5Envelope;
  522. if (width == 638 && height == 902)
  523. return PaperKind.C5Envelope;
  524. if (width == 449 && height == 638)
  525. return PaperKind.C6Envelope;
  526. if (width == 1700 && height == 2200)
  527. return PaperKind.CSheet;
  528. if (width == 433 && height == 866)
  529. return PaperKind.DLEnvelope;
  530. if (width == 2200 && height == 3400)
  531. return PaperKind.DSheet;
  532. if (width == 3400 && height == 4400)
  533. return PaperKind.ESheet;
  534. if (width == 725 && height == 1050)
  535. return PaperKind.Executive;
  536. if (width == 850 && height == 1300)
  537. return PaperKind.Folio;
  538. if (width == 850 && height == 1200)
  539. return PaperKind.GermanStandardFanfold;
  540. if (width == 1700 && height == 1100)
  541. return PaperKind.Ledger;
  542. if (width == 850 && height == 1400)
  543. return PaperKind.Legal;
  544. if (width == 927 && height == 1500)
  545. return PaperKind.LegalExtra;
  546. if (width == 850 && height == 1100)
  547. return PaperKind.Letter;
  548. if (width == 927 && height == 1200)
  549. return PaperKind.LetterExtra;
  550. if (width == 850 && height == 1269)
  551. return PaperKind.LetterPlus;
  552. if (width == 387 && height == 750)
  553. return PaperKind.MonarchEnvelope;
  554. if (width == 387 && height == 887)
  555. return PaperKind.Number9Envelope;
  556. if (width == 413 && height == 950)
  557. return PaperKind.Number10Envelope;
  558. if (width == 450 && height == 1037)
  559. return PaperKind.Number11Envelope;
  560. if (width == 475 && height == 1100)
  561. return PaperKind.Number12Envelope;
  562. if (width == 500 && height == 1150)
  563. return PaperKind.Number14Envelope;
  564. if (width == 363 && height == 650)
  565. return PaperKind.PersonalEnvelope;
  566. if (width == 1000 && height == 1100)
  567. return PaperKind.Standard10x11;
  568. if (width == 1000 && height == 1400)
  569. return PaperKind.Standard10x14;
  570. if (width == 1100 && height == 1700)
  571. return PaperKind.Standard11x17;
  572. if (width == 1200 && height == 1100)
  573. return PaperKind.Standard12x11;
  574. if (width == 1500 && height == 1100)
  575. return PaperKind.Standard15x11;
  576. if (width == 900 && height == 1100)
  577. return PaperKind.Standard9x11;
  578. if (width == 550 && height == 850)
  579. return PaperKind.Statement;
  580. if (width == 1100 && height == 1700)
  581. return PaperKind.Tabloid;
  582. if (width == 1487 && height == 1100)
  583. return PaperKind.USStandardFanfold;
  584. return PaperKind.Custom;
  585. }
  586. #endregion
  587. #region Print job methods
  588. static string tmpfile;
  589. /// <summary>
  590. /// Gets a pointer to an options list parsed from the printer's current settings, to use when setting up the printing job
  591. /// </summary>
  592. /// <param name="printer_settings"></param>
  593. /// <param name="page_settings"></param>
  594. /// <param name="options"></param>
  595. internal static int GetCupsOptions (PrinterSettings printer_settings, PageSettings page_settings, out IntPtr options)
  596. {
  597. options = IntPtr.Zero;
  598. PaperSize size = page_settings.PaperSize;
  599. int width = size.Width * 72 / 100;
  600. int height = size.Height * 72 / 100;
  601. StringBuilder sb = new StringBuilder();
  602. sb.Append(
  603. "copies=" + printer_settings.Copies + " " +
  604. "Collate=" + printer_settings.Collate + " " +
  605. "ColorModel=" + (page_settings.Color ? "Color" : "Black") + " " +
  606. "PageSize=" + String.Format ("Custom.{0}x{1}", width, height) + " " +
  607. "landscape=" + page_settings.Landscape
  608. );
  609. if (printer_settings.CanDuplex)
  610. {
  611. if (printer_settings.Duplex == Duplex.Simplex)
  612. sb.Append(" Duplex=None");
  613. else
  614. sb.Append(" Duplex=DuplexNoTumble");
  615. }
  616. return cupsParseOptions (sb.ToString(), 0, ref options);
  617. }
  618. internal static bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
  619. {
  620. DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
  621. doc.title = doc_name;
  622. return true;
  623. }
  624. internal static bool EndDoc (GraphicsPrinter gr)
  625. {
  626. DOCINFO doc = (DOCINFO) doc_info[gr.Hdc];
  627. gr.Graphics.Dispose (); // Dispose object to force surface finish
  628. IntPtr options;
  629. int options_count = GetCupsOptions (doc.settings, doc.default_page_settings, out options);
  630. cupsPrintFile (doc.settings.PrinterName, doc.filename, doc.title, options_count, options);
  631. cupsFreeOptions (options_count, options);
  632. doc_info.Remove (gr.Hdc);
  633. if (tmpfile != null) {
  634. try { File.Delete (tmpfile); }
  635. catch { }
  636. }
  637. return true;
  638. }
  639. internal static bool StartPage (GraphicsPrinter gr)
  640. {
  641. return true;
  642. }
  643. internal static bool EndPage (GraphicsPrinter gr)
  644. {
  645. GdipGetPostScriptSavePage (gr.Hdc);
  646. return true;
  647. }
  648. // Unfortunately, PrinterSettings and PageSettings couldn't be referencing each other,
  649. // thus we need to pass them separately
  650. internal static IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
  651. {
  652. IntPtr graphics = IntPtr.Zero;
  653. string name;
  654. if (!settings.PrintToFile) {
  655. StringBuilder sb = new StringBuilder (1024);
  656. int length = sb.Capacity;
  657. cupsTempFile (sb, length);
  658. name = sb.ToString ();
  659. tmpfile = name;
  660. }
  661. else
  662. name = settings.PrintFileName;
  663. PaperSize psize = default_page_settings.PaperSize;
  664. int width, height;
  665. if (default_page_settings.Landscape) { // Swap in case of landscape
  666. width = psize.Height;
  667. height = psize.Width;
  668. } else {
  669. width = psize.Width;
  670. height = psize.Height;
  671. }
  672. GdipGetPostScriptGraphicsContext (name,
  673. width / 100 * 72,
  674. height / 100 * 72,
  675. // Harcoded dpy's
  676. 300, 300, ref graphics);
  677. DOCINFO doc = new DOCINFO ();
  678. doc.filename = name.ToString();
  679. doc.settings = settings;
  680. doc.default_page_settings = default_page_settings;
  681. doc_info.Add (graphics, doc);
  682. return graphics;
  683. }
  684. #endregion
  685. #region DllImports
  686. [DllImport("libcups", CharSet=CharSet.Ansi)]
  687. static extern int cupsGetDests (ref IntPtr dests);
  688. [DllImport("libcups", CharSet=CharSet.Ansi)]
  689. static extern void cupsGetDest (string name, string instance, int num_dests, ref IntPtr dests);
  690. [DllImport("libcups")]
  691. static extern void cupsFreeDests (int num_dests, IntPtr dests);
  692. [DllImport("libcups", CharSet=CharSet.Ansi)]
  693. static extern IntPtr cupsTempFile (StringBuilder sb, int len);
  694. [DllImport("libcups", CharSet=CharSet.Ansi)]
  695. static extern IntPtr cupsGetDefault ();
  696. [DllImport("libcups", CharSet=CharSet.Ansi)]
  697. static extern int cupsPrintFile (string printer, string filename, string title, int num_options, IntPtr options);
  698. [DllImport("libcups", CharSet=CharSet.Ansi)]
  699. static extern IntPtr cupsGetPPD (string printer);
  700. [DllImport("libcups", CharSet=CharSet.Ansi)]
  701. static extern IntPtr ppdOpenFile (string filename);
  702. [DllImport("libcups", CharSet=CharSet.Ansi)]
  703. static extern IntPtr ppdFindOption (IntPtr ppd_file, string keyword);
  704. [DllImport("libcups")]
  705. static extern void ppdClose (IntPtr ppd);
  706. [DllImport ("libcups", CharSet=CharSet.Ansi)]
  707. static extern int cupsParseOptions (string arg, int number_of_options, ref IntPtr options);
  708. [DllImport("libcups")]
  709. static extern void cupsFreeOptions (int number_options, IntPtr options);
  710. [DllImport("gdiplus.dll", CharSet=CharSet.Ansi)]
  711. static extern int GdipGetPostScriptGraphicsContext (string filename, int with, int height, double dpix, double dpiy, ref IntPtr graphics);
  712. [DllImport("gdiplus.dll")]
  713. static extern int GdipGetPostScriptSavePage (IntPtr graphics);
  714. #endregion
  715. #region Struct
  716. public struct DOCINFO
  717. {
  718. public PrinterSettings settings;
  719. public PageSettings default_page_settings;
  720. public string title;
  721. public string filename;
  722. }
  723. public struct PPD_SIZE
  724. {
  725. public int marked;
  726. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
  727. public string name;
  728. public float width;
  729. public float length;
  730. public float left;
  731. public float bottom;
  732. public float right;
  733. public float top;
  734. }
  735. public struct PPD_GROUP
  736. {
  737. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=40)]
  738. public string text;
  739. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=42)]
  740. public string name;
  741. public int num_options;
  742. public IntPtr options;
  743. public int num_subgroups;
  744. public IntPtr subgrups;
  745. }
  746. public struct PPD_OPTION
  747. {
  748. public byte conflicted;
  749. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
  750. public string keyword;
  751. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
  752. public string defchoice;
  753. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
  754. public string text;
  755. public int ui;
  756. public int section;
  757. public float order;
  758. public int num_choices;
  759. public IntPtr choices;
  760. }
  761. public struct PPD_CHOICE
  762. {
  763. public byte marked;
  764. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=41)]
  765. public string choice;
  766. [MarshalAs(UnmanagedType.ByValTStr, SizeConst=81)]
  767. public string text;
  768. public IntPtr code;
  769. public IntPtr option;
  770. }
  771. public struct PPD_FILE
  772. {
  773. public int language_level;
  774. public int color_device;
  775. public int variable_sizes;
  776. public int accurate_screens;
  777. public int contone_only;
  778. public int landscape;
  779. public int model_number;
  780. public int manual_copies;
  781. public int throughput;
  782. public int colorspace;
  783. public IntPtr patches;
  784. public int num_emulations;
  785. public IntPtr emulations;
  786. public IntPtr jcl_begin;
  787. public IntPtr jcl_ps;
  788. public IntPtr jcl_end;
  789. public IntPtr lang_encoding;
  790. public IntPtr lang_version;
  791. public IntPtr modelname;
  792. public IntPtr ttrasterizer;
  793. public IntPtr manufacturer;
  794. public IntPtr product;
  795. public IntPtr nickname;
  796. public IntPtr shortnickname;
  797. public int num_groups;
  798. public IntPtr groups;
  799. public int num_sizes;
  800. public IntPtr sizes;
  801. /* There is more data after this that we are not using*/
  802. }
  803. public struct CUPS_OPTIONS
  804. {
  805. public IntPtr name;
  806. public IntPtr val;
  807. }
  808. public struct CUPS_DESTS
  809. {
  810. public IntPtr name;
  811. public IntPtr instance;
  812. public int is_default;
  813. public int num_options;
  814. public IntPtr options;
  815. }
  816. #endregion
  817. }
  818. class GlobalPrintingServicesUnix : GlobalPrintingServices
  819. {
  820. internal override PrinterSettings.StringCollection InstalledPrinters {
  821. get {
  822. return PrintingServicesUnix.InstalledPrinters;
  823. }
  824. }
  825. internal override IntPtr CreateGraphicsContext (PrinterSettings settings, PageSettings default_page_settings)
  826. {
  827. return PrintingServicesUnix.CreateGraphicsContext (settings, default_page_settings);
  828. }
  829. internal override bool StartDoc (GraphicsPrinter gr, string doc_name, string output_file)
  830. {
  831. return PrintingServicesUnix.StartDoc (gr, doc_name, output_file);
  832. }
  833. internal override bool EndDoc (GraphicsPrinter gr)
  834. {
  835. return PrintingServicesUnix.EndDoc (gr);
  836. }
  837. internal override bool StartPage (GraphicsPrinter gr)
  838. {
  839. return PrintingServicesUnix.StartPage (gr);
  840. }
  841. internal override bool EndPage (GraphicsPrinter gr)
  842. {
  843. return PrintingServicesUnix.EndPage (gr);
  844. }
  845. }
  846. }