Archive for the '.NET' Category

20
Mai
13

ProgressBar für die Console

Für ein kleines Projekt brauchte ich einen Fortschrittsbalken für eine Kommandozeilen-Applikation. Ich war erstaunt, wie einfach das funktionierte und möchte meine Erfahrungen hier teilen.

Hier schon mal ein Blick auf das Endergebnis:

image

Zuerst einmal müssen die Begrenzungen des Fortschrittsbalken gezeichnet werden.

Um den Cursor zu positionieren, kann auf die statischen Eigenschaften CursorTop und CursorLeft der Console zurückgegriffen werden:

CursorTopLeft

Hier der Code zum Erstellen der Begrenzungen des Fortschrittsbalkens:

// Create boundaries for progress bar
Console.CursorTop = topOffset;
Console.CursorLeft = leftOffset;
Console.Write("[");
Console.CursorLeft = length;
Console.Write("]");

Das sieht dann erstmal so aus:

image

 

Dann füllen wir die Begrenzungen mit dem aktuellen Fortschritt:

// Calculate size of one percent element
float progressElementSize = ((float)length – leftOffset – 2) / total;

// Create progress content
int position = 1;
Console.CursorLeft = position;
for (int i = leftOffset; i < progressElementSize * progress; i++)
{
    Console.BackgroundColor = progressColor;
    Console.CursorLeft = position++;
    Console.Write(" ");
}
Console.BackgroundColor = ConsoleColor.Black;

Und das sieht dann so aus:

image

Ganz wichtig: In der letzten Zeile wird die Farbe wieder auf schwarz gesetzt, da sonst die aktuelle Schriftfarbe auf die des Fortschritts gesetzt wird.

Abschließend will ich noch den aktuellen Fortschritt prozentual anzeigen:

// Write progress message
Console.CursorLeft = length + 2;
int result = progress * 100 / total;
Console.Write(customProgressMessage ?? (result + "%").PadLeft(4));

Das .PadLeft(4) habe ich angehängt, damit der String nicht springt, wenn von 9% auf 10% und von 99% auf 100% gesprungen wird.

Viel Spaß damit Smiley

Download: http://sdrv.ms/10HH7Pk

16
Mai
13

Die DotNet Cologne 2013 (#dnc13)

2013-05-03 09.17.38Dieses Jahr war die dotnet cologne 2013 eine besondere Konferenz für mich: ich habe erstmals auf einer Entwickler-Konferenz einen Vortrag gehalten. Das Thema war “Einstieg in das Windows Installer XML (WiX) Toolset”.

Der Raum war wirklich gut gefüllt und es hat mir wirklich viel Spaß gemacht. Auch Dank der freundlichen Unterstützung meines überraschenden  “Co-Referenten” Sebastian Seidel zu den Fragen während des Vortrags war die Session aus meiner Sicht ein Erfolg.

Die Folien habe ich auf SlideShare hochgeladen:
http://de.slideshare.net/minibrain/einstieg-in-das-windows-installer-xml-wix-toolset

Die gezeigten Codebeispiele liegen auf github:
https://github.com/minibrain/DNC13

Nach dem Vortrag gab es noch zahlreiche interessante Diskussionen zum Thema Windows Installer, MSI und Windows Installer XML Toolset. Vielen Dank an dieser Stelle nochmals an alle Teilnehmer!

Während meines Vortrags gab es noch weitere Vorträge, die mich sehr interessiert hätten. “Hackers Reverse Engineering Uncovered” von Rüdiger Kügler war einer davon. Glücklicherweise hat sich im Gespräch später am Stand von WiBu Systems ergeben, dass demnächst der Vortrag in einem webcast wiederholt wird. Das werde ich mir dieses Mal nicht entgehen lassen Smiley

Die Lunch-Session und die folgende Session stand ganz im Zeichen von Usability und User Experience. War wirklich mal interessant, einen Einblick in einen Entwicklungsprozess zu bekommen, der einen Focus auch auf Usability hat. Der Vortrag “WPF UI Development Best Practices” drehte sich im ersten Teil auch um Usability und besprach dann WPF Best Practices natürlich mit Focus auf Usability!

Timur Zanagar hat dann im Vortrag zu “Mobile .NET Entwicklung mit Xamarin 2.0” die Entwicklung mobiler Applikationen für iOS, Android, Windows Phone und MacOS unter Xamarin 2.0 gezeigt. Auch hier haben die zahlreichen Diskussionen zu einer wirklich guten Atmosphäre geführt. Hier muss ich unbedingt mal ein wenig Zeit investieren und eine eigene Android App basteln Smiley

Den Abschluss meiner .NET Cologne 2013 machte der Vortrag von Dennis Traub “Strategischer Anwendungsentwurf mit Domain-Driven Design”. Wirklich interessant, aber schon etwas schwere Kost zum Abschluss.

Alles in allem war diese dotnet cologne 2013 für mich noch etwas besser als die letztes Jahr. Die Organisatoren Albert Weinert, Roland Weigelt, Stefan Lange und Melanie Eibl haben wieder einmal eine tolle Konferenz organisiert. Dankeschön nochmals an dieser Stelle!

29
Apr
13

Drag&Drop: FileDrop aus eigener Applikation heraus

Möchte man per Drag&Drop Dateien aus dem Windows Explorer in die eigene Applikation hereinziehen, so ist das kein Problem:

  • Platzieren eines Controls, auf dem die Datei(en) per Drag&Drop gezogen werden sollen
  • Eigenschaft “AllowDrop” des Controls auf “True” setzen:

image

  • Registrieren auf die Events DragEnter und DragDrop:

image

  • Im EventHandler für DragEnter prüfen, ob es sich im Dateien und den Mauszeiger anpassen handelt:

if (e.Data.GetDataPresent("FileDrop"))
{
    e.Effect = DragDropEffects.Copy;
}

  • Im EventHandler für DragDrop die Datei auslesen (und in einer TextBox darstellen)

string[] files = e.Data.GetData("FileDrop") as string[];
if (files == null) return;

_txtContent.Text = File.ReadAllText(files[0]);

Das Resultat kann dann so aussehen:

image

Anders herum ist es jedoch etwas schwieriger: Wie kann ich Daten beispielsweise aus einer TextBox per Drag&Drop in eine Datei in den Windows Explorer droppen?

Dazu muss man sich eines kleinen Tricks behelfen: Man muss ein FileDrop initiieren und die zu droppenden Daten in eine temporäre Datei kopieren. Der Dateiname der temporären Datei ist dann auch der Dateiname des Drop Targets. Hier ist eine kleine Schritt-für-Schritt Anleitung:

  • Registrieren auf das MouseDown Event als Initiator für die Drag&Drop Aktion:

image

  • Anlegen einer temporären Datei mit dem Inhalten, die in die zu droppende Datei geschrieben werden sollen. Wichtig: Der Dateiname ist auch der Dateiname der dort erstellt wird, wo die Datei im Explorer gedropped wird:

// Create temporary file name
string tempFile = Path.Combine(Path.GetTempPath(), "LoremIpsum.txt");

  • Inhalt in die temporäre Datei schreiben

// Write content to drop into the temporary file
File.WriteAllText(tempFile, _txtContent.Text);

  • Temporäre Date in ein string-Array verpacken (wird benötigt, da FileDrop ein string array erwartet):

// Create string-array for FileDrop operations
string[] files = new[] { tempFile };

  • DataObject erstellen und mit dem Format der Daten (“FileDrop”) und den Daten instanziieren:

// Create DataObject for "FileDrop" and add string[] with temporary file
DataObject dataObject = new DataObject("FileDrop", files);

  • DragDrop initiieren und dataObject übergeben:

// Initiate DragDrop operation
DoDragDrop(dataObject, DragDropEffects.All);

08
Sep
12

System.IO.FileLoadException: Verwenden von .NET 2.0 Assemblies innerhalb eines .NET 4.0 Prozesses

Verwendet eine .NET 4.0 Assembly .NET 2.0 Komponenten, kommt es zu einer System.IO.FileLoadException mit der detaillierten Meldung „Die Assembly im gemischten Modus wurde während Version v2.0.50727 der Laufzeit erstellt und kann nicht während der 4.0-Laufzeit ohne zusätzliche Konfigurationsinformationen geladen werden.“:

Bei mir lag es einfach daran, dass ich eine UI-Bibliothek verwendete, die für die CLR 2.0 entwickelt wurde, während mein Hauptprojekt in .NET 4.0 entwickelt wurde.

Es gibt mehrere Möglichkeiten, das Problem zu lösen:

–          Über eine Konfigurationsdatei

–          Über das Konfigurierung der Aktivierung via Code

Lösungsmöglichkeit 1: via Konfigurationsdatei

<startup useLegacyV2RuntimeActivationPolicy=“true“>
<supportedRuntime version=“v4.0″/>
</startup>

Die app.config muss natürlich neben der ausführbaren Datei stehen.

Beispiel:

Ausführbare Datei: example.exe
Konfigurationsdatei: example.exe.config

Mark Miller hat in einem Blog-Beitrag (als PDF: marklio – What is useLegacyV2RuntimeActivationPolicy for_) beschrieben, wozu die useLegacyV2RuntimeActivationPolicy nun wirklich gut ist und was sie tut.

Es gibt jedoch Anwendungsfälle, für die man nicht einfach eine Konfigurationsdatei neben die ausführbare Datei legen kann. Ein Beispiel dafür könnte sein, dass eine C-API oder eine COM-API zur Verfügung gestellt wird. Dann kann nicht einfach der ausführbaren Datei, die die C-API verwendet, eine Konfigurationsdatei beigelegt werden.

Lösungsmöglichkeit 2: via Code

Im Blog von Reed Copsey bin ich auf einen interessanten Artikel gestoßen, der genau mein Problem löst: http://reedcopsey.com/2011/09/15/setting-uselegacyv2runtimeactivationpolicy-at-runtime/

Nachfolgend der Code, der für meine Belange (C-API) funktionierte. Jedoch ist die Lösung in Reed Copseys Blog explizit als inoffiziell gekennzeichnet.

public static bool LegacyV2RuntimeEnabledSuccessfully { get; private set; }

staticRuntimePolicyHelper()

{

ICLRRuntimeInfoclrRuntimeInfo =   (ICLRRuntimeInfo)RuntimeEnvironment.GetRuntimeInterfaceAsObject(Guid.Empty,  typeof(ICLRRuntimeInfo).GUID);

try

{

clrRuntimeInfo.BindAsLegacyV2Runtime();

LegacyV2RuntimeEnabledSuccessfully = true;

}

catch (COMException)

{

// This occurs with an HRESULT meaning

// „A different runtime was already bound to the legacy CLR version 2 activation policy.“

LegacyV2RuntimeEnabledSuccessfully = false;

}

}

[ComImport]

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

[Guid(„BD39D1D2-BA2F-486A-89B0-B4B0CB466891“)]

private interface ICLRRuntimeInfo

{

void xGetVersionString();

void xGetRuntimeDirectory();

void xIsLoaded();

void xIsLoadable();

void xLoadErrorString();

void xLoadLibrary();

void xGetProcAddress();

void xGetInterface();

void xSetDefaultStartupFlags();

void xGetDefaultStartupFlags();

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]

void BindAsLegacyV2Runtime();

}

Interessanterweise wird ein statischer Konstruktor verwendet, der unmittelbar nach dem Laden der assembly ausgeführt wird. Dadurch wird der Code implizit von der Runtime ausgeführt und nicht explizit vom Programm selbst. Das sollte ausreichend gut dokumentiert werden, da potentiell nicht jeder im Team den Code sofort versteht und potentiell den Code als „unnütz“ löschen könnte 😉

Die Eigenschaft „LegacyV2RuntimeEnabledSuccessfully“ gibt an, ob das Umschalten der Runtime-Aktivierung funktioniert hatte. In meinem Fall habe ich eine Ausgabe für die API erstellt, die dem Benutzer angibt, wie er das Problem mithilfe der Konfigurationsdatei lösen kann.

02
Aug
08

Tutorial iTextSharp: Erstellen von PDF-Objekten

Texte

In iTextSharp werden Texte mithilfe von drei Klassen zusammengesetzt: Chunk, Phrase und Paragraph. Diese sollen in den nächsten Zeilen etwas näher beschrieben werden.

Chunk

Die Klasse Chunk befindet sich im Namespace iTextSharp.text. Chunk stellt die „kleinste“ Einheit in iTextSharp dar. Es besteht aus einem String, bei dem alle Zeichen die gleiche Formatierung (also Schriftart, -größe, -stil und -farbe) besitzen.

Chunk-Objekte besitzen keinerlei Informationen über Zeilenabstände. Das heißt, dass wenn der enthaltene String zu lang ist, wird ein Wagenrücklauf (Carriage return) ohne Zeilenvorschub ausgelöst. Das Resultat ist das, dass die gerade geschriebene Zeile überschrieben wird (ohne gelöscht zu werden). Deshalb sollten Chunk-Objekte in der Regel nicht dazu verwendet werden, direkt einem Dokument hinzugefügt zu werden. Stattdessen sollten sie in Kombination mit anderen Objekten verwendet werden.

Code-Beispiel

Document doc = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.GetInstance(doc, File.Create(„Zitate.pdf“));
doc.Open();
Chunk zitatEinstein = new Chunk(„Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.“);
Chunk zitatTwain = new Chunk(„Gib jedem Tag die Chance, der schönste deines Lebens zu werden.“);
doc.Add(zitatEinstein);
doc.Add(zitatTwain);
doc.Close();

Ausgabe im Adobe Reader

image

Phrase

Ein Phrase-Objekt (engl. Satz) besteht aus einer Aneinanderreihung von Chunk-Objekten mit einem wichtigen Extra: Wenn ein Zeilenende erkannt wird, dann wird neben den Wagenrücklauf (Carriage Return) auch ein Zeilenvorschub (New Line / Line Feed) ausgelöst, sodass sich die Chunks nicht mehr überschreiben. Der Zeilenabstand wird auch als Leading bezeichnet und kann im Konstruktor als auch in der Leading-Eigenschaft der Phrase-Klasse als float-Wert angegeben werden.

Zusätzlich ist es möglich, eine Hauptschriftart anzugeben, mit der das Phrase-Objekt formatiert wird. Somit erhalten alle enthaltenen Chunk-Objekte die gleiche Formatierung und ein einheitliches Aussehen. Aber ebenso kann man auch jedes Chunk-Objekt einzeln formatieren.

Code-Beispiel

Document doc = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.GetInstance(doc, File.Create(„Zitate.pdf“));
doc.Open();
Chunk zitatEinstein = new Chunk(„Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.“);
Chunk zitatTwain = new Chunk(„Gib jedem Tag die Chance, der schönste deines Lebens zu werden.“);
Phrase zitate = new Phrase(25);
zitate.Add(zitatEinstein);
zitate.Add(zitatTwain);
doc.Add(zitate);
doc.Close();

Ausgabe im Adobe Reader

image

Paragraph

Das Paragraph-Objekt verbindet mehrere Chunk- und Phrase-Objekte zu einem Absatz (Paragraph, engl. Absatz). Nach jedem Absatz wird automatisch ein Zeilenumbruch erstellt. Das entspricht etwa dem, dass man einem Phrase-Objekt ein Chunk.NEWLINE oder new Chunk(„\n“) anhängt.

Die Paragraph-Klasse leitet von der Phrase-Klasse ab und ergänzt diese um einige Funktionen:

image

Abbildung 3: Klassenhierarchie bei Phrase und Paragraph

Der Zusammenhang zwischen Chunk, Phrase und Paragraph soll in folgender Abbildung verdeutlicht werden:

Bild1

Abbildung 4: Zusammenhang zwischen Paragraph, Phrase und Chunk

Initialisierung

Die Paragraph-Klasse besitzt mehrere Konstruktoren:

public Paragraph()
public Paragraph(float leading)
public Paragraph(Chunk chunk)
public Paragraph(float leading, Chunk chunk)
public Paragraph(string str)
public Paragraph(string str, Font font)
public Paragraph(float leading, string str)
public Paragraph(float leading, string str, Font font)
public Paragraph(Phrase phrase)

Ein Absatz kann also aus Chunks, Phrases oder String-Objekten erstellt werden. Über das Font-Objekt kann eine beliebige Schriftart für den Absatz festgelegt werden.

Abstand zwischen den Zeilen festlegen

Zusätzlich unterstützen einige Konstruktoren die Definition von Zeilenabständen (hier leading genannt). Alternativ kann über die Leading-Eigenschaft der Zeilenabstand festgelegt werden.

Abstand zwischen Absätzen festlegen

Den Abstand zwischen einzelnen Absätzen kann über die Eigenschaften SpacingBefore und SpacingAfter gesteuert werden. Dabei wird der angegebene Wert zu dem Wert addiert, der als leading definiert wurde.

Ausrichtung

Als „Besonderheit“ beim Paragraph-Objekt ist die Möglichkeit, Textausrichtungen vorzunehmen. Dazu wird die Methode SetAlignment verwendet. Als Parameter wird ein String erwartet, der als Konstante in ElementTag-Klasse festgelegt ist. Mögliche Werte sind: ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFIED, ALIGN_JUSTIFIED_ALL, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM und ALIGN_BASELINE.

Ebenso wäre es möglich, anstatt die SetAlignment-Methode zu verwenden, der Alignment-Eigenschaft einen Wert zuzuweisen. Dieser Wert muss dabei vom Typ integer sein. Auch hier gibt es wieder Konstanten, die zum Setzen der richtigen Ausrichtung verwendet werden – allerdings sind sie in der Element-Klasse definiert: ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFIED, ALIGN_JUSTIFIED_ALL, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM und ALIGN_BASELINE.

Wann man welche Methode verwendet, ist reine Geschmackssache. Intern wird SetAlignment auf Alignment gemappt.

Nachfolgend ein paar Code-Beispiele für die Textausrichtung im Absatz:

Document doc = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.GetInstance(doc, File.Create(„Zitate.pdf“));
doc.Open();
Chunk zitatTwain = new Chunk(„Gib jedem Tag die Chance, der schönste deines Lebens zu werden.“);
zitatTwain.Font = FontFactory.GetFont(„Tahoma“, 24);
Paragraph paragraphTwain = new Paragraph(zitatTwain);

Setzen der Ausrichtung über SetAlignment-Methode

paragraphTwain.SetAlignment(ElementTags.ALIGN_CENTER);
doc.Add(paragraphTwain);
paragraphTwain.SetAlignment(ElementTags.ALIGN_LEFT);

Setzen der Ausrichtung über Alignment-Eigenschaft

doc.Add(paragraphTwain);
paragraphTwain.Alignment = Element.ALIGN_RIGHT;
doc.Add(paragraphTwain);
doc.Close();

Ausgabe im PDF

image

Einrückungen am Absatzanfang

Weiterhin besitzt das Paragraph-Objekt noch die Möglichkeit, Einrückungen am Anfang eines Absatzes einzufügen. Die wird mithilfe der IdentationLeft- und IdentationRight-Eigenschaft.

02
Aug
08

Tutorial iTextSharp: Writer & Meta-Daten

Das Writer-Objekt

Nachdem nun das Document-Objekt definiert wurde, wird zum Schreiben ein Writer-Objekt benötigt. Dieses entscheidet, wie das Dokument später geschrieben wird. Für jeden „Dokumenttyp“ gibt es ein Writer-Objekt: Beispielsweise wird für PDF-Dokumente ein PdfWriter benötigt, während für TeX-Dokumente ein TeXWriter instanziiert werden muss usw. Das Konzept von iTextSharp ermöglicht auch eine Dokumenttypen und –writer zu erstellen. Diese müssen nur von der abstrakten Klasse DocWriter aus dem iTextSharp.text-Namespace abgeleitet sein.

image

Abbildung 1: Klassenhierarchie DocWriter

Der Konstruktor der Writer-Klassen ist nicht öffentlich (private), sodass mittels GetInstance-Methode ein neues Objekt erzeugt werden muss. GetInstance erwartet zwei Parameter: das Document-Objekt (Das Document-Objekt) und einen Stream, in den die Ausgabe geschrieben wird.

Beispiel für das Erstellen eines neuen PDF-Writers:

Document doc = new Document(PageSize.A4.Rotate());

PdfWriter writer = PdfWriter.GetInstance(doc, File.Create(„test.pdf“));

Zum Schreiben einer PDF-Datei wird das writer-Objekt nicht mehr direkt verwendet (natürlich hält jedes Writer-Objekt einen IDocListener auf das Document-Objekt und wird somit über Änderungen im Document informiert). Stattdessen ermöglicht es weitere Features, auf die in den entsprechenden Kapiteln eingegangen wird:

  • Bearbeiten vorhandener PDF-Dokumente
  • Direktes Zeichnen von Grafiken
  • Verschlüsseln von PDF-Dokumenten
  • Viewer-Einstellungen vornehmen (Anzeige mit/ohne Menüleiste, Vollbild-Modus, Vorschaubilder anzeigen, Seiten-Skalierung etc.)
  • Dateien anhängen

PDF Meta-Daten bearbeiten

Die Meta-Daten im PDF-Dokument beinhalten allgemeine Informationen über das Dokument. Im Adobe Acrobat Reader können die Meta-Daten in den Dokumenteigenschaften (Datei à Dokumenteigenschaften / Strg + D) angesehen werden:

image

Abbildung 2: PDF-Metadaten

Rot hervorgehoben sind die jeweiligen Metadaten, die programmatisch auf dem Document-Objekt gesetzt werden können:

Eigenschaft in den Metadaten

image

Beispiel für das Setzen der Meta-Daten:

doc.AddAuthor(„Ralf Abramowitsch“);
doc.AddCreationDate();
doc.AddCreator(„Mein Tool“);
doc.AddKeywords(„iTextSharp“);
doc.AddKeywords(„Tutorial“);
doc.AddKeywords(„.NET“);
doc.AddSubject(„Thema“);
doc.AddTitle(„Titel“);
doc.AddProducer();

02
Aug
08

Tutorial iTextSharp: Einführung

iTextSharp ist eine Open Source Bibliothek zum Erstellen und Bearbeiten von PDF-Dateien. Die Java-Bibliothek iText wurde auf .NET (C#) portiert und wird synchron mit dem .NET-Pendant weiterentwickelt.

Ziel der Entwicklung war Entwicklern eine Bibliothek in die Hand zu geben, mit der sie ihre eigenen Anwendungen um PDF-Funktionalitäten erweitern konnten. In diesem Tutorial soll darum gehen, einzelne Funktionalitäten von iTextSharp anhand von Beispielen vorzustellen.

Bezugsmöglichkeiten

iText: http://www.lowagie.com/iText

iTextSharp: http://sourceforge.net/projects/itextsharp/

Tipp: Code-Dokumentation mit Doxygen erzeugen

Ich habe mich immer gefragt, warum ich denn bei IntelliSense keine Hilfe zu sehen bekomme. Ist der Code schlecht oder gar nicht dokumentiert? Nein! Der Autor hat darauf verzichtet, Kommentare im .NET-Format zu verfassen, stattdessen hat er auf das Doxygen-Format zurückgegriffen.

Somit werden keine Kommentare in die Metadaten exportiert und IntelliSense kann diese nicht auslesen. Daher ist jeder gut beraten, sich die Dokumentation kurz selbst zu erzeugen. Dazu lädt man einfach das letzte Doxygen Release von http://www.stack.nl/~dimitri/doxygen/ herunter.

Erstellen von PDF-Dokumenten

Das Document-Objekt

Das Document-Objekt stellt die Basis aller Dokument-Typen der iTextSharp-Bibliothek dar. Das Document-Objekt besitzt drei öffentliche Konstruktoren:

public Document()

public Document(Rectangle pageSize)

public Document(Rectangle pageSize, int marginLeft,int marginRight,

int marginTop, int marginBottom)

Definition der Seitengröße

Der parameterlose Konstruktor von Document verwendet als Default-Einstellung die Seitengröße A4, während die anderen beiden Konstruktoren eine Angabe der Seitengröße erwarten. Bei deren Definition kann auf die Klasse PageSize zurückgegriffen werden. PageSize besitzt öffentliche Felder, die die Auswahl von Seitengrößen vereinfacht. Mögliche Werte sind: A0 … A10, B0 … B10, HALFLETTER, LETTER, EXECUTIVE, LEGAL, NOTE, POSTCARD und einige mehr.

Definition des Seitenformats

Neben der eigentlichen Größe des PDF-Dokuments kann man auch dessen Ausrichtung, also Hochformat oder Querformat festlegen. Die Standard-Einstellung ist dabei Hochformat. Um eine Seite im Querformat anzulegen, ruft man einfach die Methode „rotate()“ auf dem von PageSize zurückgegebenen Wert auf. Ein PDF-Dokument im Querformat der Größe A4 würde wie folgt definiert werden:

Document doc = new Document(PageSize.A4.Rotate());

Definition der Seitenränder

Der dritte Konstruktor von Document bietet zudem noch die Möglichkeit, die Größe von Seitenrändern zu definieren. Die Angabe der Größe erfolgt in der Einheit „Point“ (Punkte). Die Umrechnung von „Point“ in „Zentimeter“ ist etwas umständlich, da die 72 Points genau ein Zoll darstellt. Ein Zoll wiederum besteht aus 2,54cm. Seitenränder von jeweils 2cm entsprechen also 56,693Points und werden wie folgt berechnet:

Ein PDF-Dokument der Seitengröße A4 mit jeweils 2cm Seitenrändern würde so erstellt werden:

Document doc = new Document(PageSize.A4.Rotate(), 28, 28, 28, 28);

image

Öffnen und Schließen des Documents

Document besitzt zwei wesentliche Funktionen, die zum Erstellen des PDF-Dokuments notwendig sind: Open() und Close():

Open() / IsOpen()
Um ein Dokument zu bearbeiten bzw. mit Inhalten zu befüllen, muss es geöffnet werden. Dazu ruft man die Methode Open() auf dem Document-Objekt auf. Über die Methode IsOpen() kann man abfragen, ob das Dokument bereits mit Open() geöffnet wurde.
Hinweis: Nachdem Open() aufgerufen wurde, kann man weder Meta-Daten noch PDF-Header-Informationen bearbeiten!

Close()
Sobald alle Inhalte dem Dokument hinzugefügt wurden, muss das Dokument geschlossen werden, damit es korrekt (auf die Festplatte) geschrieben werden kann. Nach dem Aufruf von Close() kann nichts mehr hinzugefügt werden.




Blog Stats

  • 193,100 hits