PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Drawing/System.Drawing.Printing/PrintingServicesUnix.cs

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