A minap egy érdekes problémába ütköztem. Fejlesztek egy Mono-s alkalmazást, melynek mind Linux-on mind Windows-on futnia kell és ami a lényeg, nyomtatni is kell a programból. A program felületét Gtk#-al oldottam meg a platformfüggetlenség miatt, így a natív kinézet mindkét platformon megoldott és problémamentes. Voltak kísérleteim a Windows.Forms-al is, ez azonban a Mono-ban még nagyon hiányos. A Gtk pedig egyébként is közelebb áll a szívemhez. A fejlesztés egyik kritikus pontja volt a megfelelő felület kiválasztása, amely a Gtk#-al meg is oldódott. Nem is gondoltam, hogy a nyomtatás lesz az a terület, amely a legkomolyabb hiányosságokat fogja mutatni.

Egy szó mint száz a fejlesztés azon szakaszához értem, ahol a nyomtatás került volna megvalósításra, azonban azt kellett, hogy tapasztaljam ez nem fog olyan könnyen menni mint ahogyan azt előzőleg gondoltam. A .NET keretrendszerben a System.Drawing.Printing névtér felelős a nyomtatások megvalósításáért. Íme egy egyszerű példa:

public void Printing(string printer)
{
    try {
        streamToPrint = new StreamReader (filePath);
        try {
            PrintDocument pd = new PrintDocument();
            pd.PrintPage += new PrintPageEventHandler (ppEventHandler);
            pd.PrinterSettings.PrinterName = "HP_LJ4540";
            if (pd.PrinterSettings.IsValid) {
                pd.Print();
            }
            else
                System.Console.WriteLine("Printer is invalid...");
        }
        finally {
            streamToPrint.Close();
        }
    }
    catch(Exception ex) {
        System.Console.WriteLine("Error: {0}", ex.Message);
    }
}

Az első probléma a PrinterSettings.InstalledPrinters property használatával jön elő. Ez a property volna felelős a renszerben telepített nyomtatók lekérdezéséért, melyeket egy StringCollection-ön keresztül ad vissza. Mono-val futtatva a kódot azonban NotImplementedException-el áll le futás a fenti nyomató lekérdezéshez érve. Ez összességében véve még nem jelentett volna számomra túl nagy problémát, hiszen a probléma áthidalható lenne. A beállításokat tartalmazó XML file-ba fel lehetne venni egy olyan értéket amely a program számára alapértelmezett – és természetesen a rendszerben telepített – nyomtató nevét tartalmazza és a programból csak azt kérdezném le. De mint kiderült ez csak a kisebbik probléma. Tulajdonképp a nyomtatás a Mono-ban – úgy ahogy van – még erős fejlesztés alatt áll. A PrintDocument.Print() metódus egy – ha több oldalas a dokumentum akkor több – Jpeg képet generál az aktuális könyvtárba ‘documentname xxxx.jpg’ néven, ahol az xxxx az oldal számát reprezentálja. A jelnség okát a forráskód OnEndPage() metódusában meg is találhatjuk:

public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
{
    //TODO: print current page
    // - image to print is this.image
    // - page settings are in e.PageSettings
    // - printer settings are in document.PrinterSettings
    // - don't forget to use document.OriginAtMargins (only if .NET 1.1)

    // actually, "print" == "save to a file"
    try {
        string fileName = document.DocumentName + " " + page.ToString("D4") + ".jpg";
        Console.WriteLine("StandardPrintController: Print page \"{0}\"", fileName);
        image.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
    }
    catch (Exception) {}
    if (e.Graphics != null) e.Graphics.Dispose();
}

Gondoltam arra, hogy számomra a generált Jpeg file-ok is megfelelőek lesznek a nyomtatási produktum előállításához, hiszen az lpr parancsot megfelelően felparaméterezve “bemásolhatom” a képet a nyomtatási sorba – amennyiben Linuxon fut a kód – és azzal le is tudtam a nyomtatást. Az elkészült kép minősége Linuxon azonban hagy némi kivetni valót maga után. Igényes minődégű dokumentumok sajnos így nem nyomtathatóak. Ott volna még az a lehetőség, hogy az OnEndPage() metódusban a System.Drawing.Imaging.ImageFormat osztály kimenetét TIFF-re, PNG-re vagy esetleg BMP-re módosítva javítani lehet a minőségen. Be kell azonban látni, hogy a Mono mainstream kódját módosítani önös célok érdekében nem érdemes, sőtt tűzzel, vassal megelőzendő.

Alternatív megoldást kellet, hogy találjak. Na igen, ott volt még a libgnomeprint, de irtóztam attól, hogy két eltérő megoldással működjön a nyomtatás – vagy bármely más funkciója a programnak – attól függően, hogy milyen platformon fut. Ez elsősorban a programozói lustaságomnak köszönhető, de egyébként sem tartom szerencsésnek, hogy a kód ennyire szerteágazzon.

Szerencsére találtam egy módszert, amely kiválóan megfelel az igényeimnek. Lehet, hogy nevetséges, de működik. Találtam a SourceForge-on egy library-t amely PDF file-ok készítésére alkalmas. A library neve sharpPDF. Ezt hozzáadva a kódunkhoz, játszi könnyedséggel tudunk készíteni futás időben PDF dokumentumokat, amelyet aztán az adott platformon – bármely PDF nézegetővel – már küldhetünk is a nyomtatóra. Egy sharpPDF példa:

pdfDocument myDoc = new pdfDocument("HelloWorld","ME");
pdfPage myPage = myDoc.addPage();
myPage.addText("Hello World!",200,450,predefinedFont.csHelvetica,20);
myDoc.createPDF("/tmp/test.pdf");
myPage = null;
myDoc = null;

Látható, hogy a library-t tényleg nagyon egyszerű használatba venni. Én a programban úgy oldottam meg, hogy a konfigurációs XML file tartalmat egy bejegyzést a PDF nézegetőre vonatkozóan:

/usr/bin/gpdf

Ezt felhasználva a kódból, az alkalmazást felparaméterezve a generált PDF dokumentummal már látható és nyomtatható is az elkészült anyag:

private Config cfg = new Config();
try {
    myDoc.createPDF(System.IO.Path.Combine(cfg.GetTempPath(), "szamla.pdf"));
}
catch (System.Exception ex) {
    System.Console.WriteLine("Error: {0}", ex.Message);
}
System.Diagnostics.Process.Start(cfg.GetProperty("PDFviewer"), System.IO.Path.Combine(cfg.GetTempPath(), "szamla.pdf"));

Végül így sikerült megoldanom a Mono-ban jelenleg még hiányos nyomtatási függvények mellőzését.

Tagged with:
 

One Response to Mono C# nyomtatás

  1. Mononyomtatás szerint:

    Kár, hogy 6 évvel ezelőtt nem találkoztam ezzel a cikkel.

MINDEN VÉLEMÉNY SZÁMÍT!

Email cím (nem tesszük közzé) A kötelezően kitöltendő mezőket * karakterrel jelöljük

*

A következő HTML tag-ek és tulajdonságok használata engedélyezett: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">