# html datei drucken



## mäcjava (26. Mai 2009)

Hallo,

ich arbeite mit Eclipse und habe im workspace eine html datei liegen. Diese möchte ich einfach ausdrucken[mit meinem echten Drucker von canon ] lassen. Kennt jemand dazu ein Beispiel ???

Danke


----------



## AmunRa (27. Mai 2009)

Öffne sie mit Notepad und geh auf Drucken


----------



## mäcjava (27. Mai 2009)

ich meine eigentlich als java befehl ...???


----------



## madboy (27. Mai 2009)

Willst du ASCII-Zeichen drucken oder gerendertes HTML (also so wie es im Browser angezeigt wird)?
Wobei ich beides noch nicht versucht hab eigentlich ;-)

Hier könntest du aber fündig werden: Lesson: Printing (The Java™ Tutorials > 2D Graphics).


----------



## mäcjava (27. Mai 2009)

hi - danke für deine antwort
ich möchte das so mit über einen java befehl drucken lassen, wie es auch im browser dargestellt wird. Also eigentlich nur ein Druckbefehl für eine Datei.


----------



## madboy (27. Mai 2009)

Das hatte ich befürchtet ;-)
Wie gesagt habe ich noch nie was mit Java gedruckt, aber ich vermute das ist nicht ganz trivial was du vor hast. Schon die saubere Darstellung ist nur mit Java ein mittelgroßes Problem.

Das alles hängt aber sehr stark von der "Komplexität" der Seite ab, die du drucken willst. Nicht mal Webbrowser (die ja eigentlich nicht viel anderes können sollen bzw. müssen) sind mit Webseiten bzw. den zugrunde liegenden Standards teils überfordert. Siehe ACID-Tests.

Meiner Meinung nach einfachste Lösung mit vernünftiger Darstellung: versuche, einen Webbrowser mittels eines Skriptes zu steuern und zum Drucken zu bewegen.
Ich lasse mich natürlich gern eines besseren belehren falls sonst jemand eine Idee hat 

EDIT: bevor wir hier mit Kanonen auf Spatzen schießen wäre es vielleicht nicht verkehrt, wenn du die Seite, die du drucken willst mal posten könntest. Vorausgesetzt, du willst nicht beliebige Seiten drucken...


----------



## mäcjava (27. Mai 2009)

die html seite, die ich drucken will ist nichts besonderes, da sind eine tabelle und 2 grafiken enthalten und etwas text, sonst keine besonderen elemente, also wenn ich es schaffe, die google startseite zu drucken, dann wäre mein ziel erreicht  Die zu druckende Seite wird zudem in meinem Programm in einem JEditorPane angezeigt. Vielleicht kann man das damit einfacher drucken ???


----------



## faetzminator (28. Mai 2009)

Wenn du ein bestimmtes Format drucken willst, welches einfach auch per HTML angezeigt werden soll, würde ich dies grafisch (als Bild) lösen.


----------



## Wildcard (28. Mai 2009)

Entweder du startest einen PrintJob mit dem Rendering Resultat der JEditorPane/JTextPane (die HTML Fähigkeiten sind sehr eingeschränkt), oder du lässt das Betriebssystem sich darum kümmern:
Desktop (Java Platform SE 6)


----------



## mäcjava (28. Mai 2009)

Das Drucken des Rendering Resultat der JEditorPane hört sich gut an: kennt jemand dazu ein Code - Beispiel ???


----------



## wertho (28. Mai 2009)

Zur Darstellung von HTML solltest Du besser folgende Komponente nutzen:
https://xhtmlrenderer.dev.java.net

Ein Beispiel zum Drucken gibt es hier:
The Flying Saucer User's Guide

Die Komponente beherrscht auch die Ausgabe als Grafik oder PDF.


----------



## mäcjava (28. Mai 2009)

Hi danke für den Hinweis: Ich habe das mal ausprobiert, bekomme dabei aber immer Exceptions:

	JFrame f1 = new JFrame("Test");
		f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f1.setSize(800,800);

		XHTMLPanel panel1 = new XHTMLPanel();

		f1.add(panel1);

		panel1.setDocument(new File("file:///C:/Schule/test.html"));

               f1.setVisible(true);


Was mach ich da falsch ?

FEHLER:  'Stream closed'
Exception in thread "main" org.xhtmlrenderer.util.XRRuntimeException: Can't load the XML resource (using TRaX transformer). java.io.IOException: Stream closed
	at org.xhtmlrenderer.resource.XMLResource$XMLResourceBuilder.createXMLResource(XMLResource.java:191)
	at org.xhtmlrenderer.resource.XMLResource.load(XMLResource.java:71)
	at org.xhtmlrenderer.swing.NaiveUserAgent.getXMLResource(NaiveUserAgent.java:211)
	at org.xhtmlrenderer.swing.BasicPanel.loadDocument(BasicPanel.java:468)
	at org.xhtmlrenderer.simple.XHTMLPanel.setDocument(XHTMLPanel.java:211)
	at Verwaltung.create(Verwaltung.java:22)
	at test.main(test.java:9)
Caused by: javax.xml.transform.TransformerException: java.io.IOException: Stream closed
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(Unknown Source)
	at org.xhtmlrenderer.resource.XMLResource$XMLResourceBuilder.createXMLResource(XMLResource.java:189)
	... 6 more
Caused by: java.io.IOException: Stream closed
	at java.io.BufferedInputStream.getInIfOpen(Unknown Source)
	at java.io.BufferedInputStream.fill(Unknown Source)
	at java.io.BufferedInputStream.read(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
	at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
	at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(Unknown Source)
	... 9 more


----------



## Guybrush Threepwood (28. Mai 2009)

Hi XHTMLRenderer akzeptiert nur sauberen XHTML-Code und ist sehr streng. Da fliegt sofort eine Exception, wenn etwas nicht stimmt. Eine Alternative über die bereits erwähnte Desktop-Klasse:


```
try {
					Desktop d = Desktop.getDesktop();
					d.print(htmlFile);
				} catch (Exception e1) {
					JOptionPane.showMessageDialog(null,
							"Ausdruck nicht möglich!");
				}
```


----------



## faetzminator (28. Mai 2009)

XHTML ist valides XML - im Vergleich zu HTML. ich würde dir aber diesen Weg empfehlen


----------



## mäcjava (28. Mai 2009)

@Guybrush Threepwood

Was setze ich denn in deinem Beispiel genau für htmlFile ein ???


----------



## Guybrush Threepwood (28. Mai 2009)

Da muss Dein HTMl-File-Object rein, als etwas wie z. B. :

```
File htmlFile = new File("c:\temp\test.html");
```


----------



## mäcjava (28. Mai 2009)

läuft doch hammer - -gut gemacht


----------



## mäcjava (29. Mai 2009)

also das :

try {
                    Desktop d = Desktop.getDesktop();
                    d.print(htmlFile);
                } catch (Exception e1) {
                    JOptionPane.showMessageDialog(null,
                            "Ausdruck nicht möglich!");
                }

funktioniert echt super. Gibt es eine Möglichkeit den Druckvorgang sofort zu starten, ohne das man vorher noch das Druckfenster bestätigen muss. Ich weiß, dass ist wahrscheinlich etwas anspruchsvoll, aber wenn man mehrere Dokumente auf einmal drucken will kommen da  "n" Druckfenster, die alle bestätigt werden wollen. Danke....


----------



## Guybrush Threepwood (29. Mai 2009)

Vielleicht noch nach als Nachtrag: Gestern habe ich die Druckmethode auf einem Rechner getestet und eine IOException-Exception bekommen. Offensichtlich war im System kein Standardprogramm zum Ausdrucken von HTML registriert. Mit dem DocumentRenderer klappt es dann aber doch (ich weiß allerdings nicht mehr, wo ich mir das "ergoogelt" habe, ist schon so lange her):

```
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.JEditorPane;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
import javax.swing.text.View;
import javax.swing.text.html.HTMLDocument;

public class DocumentRenderer implements Printable {

	protected int currentPage = -1; // Used to keep track of when

	// the page to print changes.

	protected JEditorPane jeditorPane; // Container to hold the

	// Document. This object will
	// be used to lay out the
	// Document for printing.

	protected double pageEndY = 0; // Location of the current page

	// end.

	protected double pageStartY = 0; // Location of the current page

	// start.

	protected boolean scaleWidthToFit = true; // boolean to allow control over

	// whether pages too wide to fit
	// on a page will be scaled.

	/*
	 * The DocumentRenderer class uses pFormat and pJob in its methods. Note
	 * that pFormat is not the variable name used by the print method of the
	 * DocumentRenderer. Although it would always be expected to reference the
	 * pFormat object, the print method gets its PageFormat as an argument.
	 */
	protected PageFormat pFormat;

	protected PrinterJob pJob;

	/*
	 * The constructor initializes the pFormat and PJob variables.
	 */
	public DocumentRenderer(PageFormat pForm, String jobName) {
		pFormat = pForm;
		pJob = PrinterJob.getPrinterJob();
		pJob.setJobName(jobName);
	}

	/*
	 * Method to get the current Document
	 */
	public Document getDocument() {
		if (jeditorPane != null)
			return jeditorPane.getDocument();
		else
			return null;
	}

	/*
	 * Method to get the current choice the width scaling option.
	 */
	public boolean getScaleWidthToFit() {
		return scaleWidthToFit;
	}

	/*
	 * pageDialog() displays a page setup dialog.
	 */
	public void pageDialog() {
		pFormat = pJob.pageDialog(pFormat);
	}

	/*
	 * The print method implements the Printable interface. Although Printables
	 * may be called to render a page more than once, each page is painted in
	 * order. We may, therefore, keep track of changes in the page being
	 * rendered by setting the currentPage variable to equal the pageIndex, and
	 * then comparing these variables on subsequent calls to this method. When
	 * the two variables match, it means that the page is being rendered for the
	 * second or third time. When the currentPage differs from the pageIndex, a
	 * new page is being requested.
	 * 
	 * The highlights of the process used print a page are as follows:
	 * 
	 * I. The Graphics object is cast to a Graphics2D object to allow for
	 * scaling. II. The JEditorPane is laid out using the width of a printable
	 * page. This will handle line breaks. If the JEditorPane cannot be sized at
	 * the width of the graphics clip, scaling will be allowed. III. The root
	 * view of the JEditorPane is obtained. By examining this root view and all
	 * of its children, printView will be able to determine the location of each
	 * printable element of the document. IV. If the scaleWidthToFit option is
	 * chosen, a scaling ratio is determined, and the graphics2D object is
	 * scaled. V. The Graphics2D object is clipped to the size of the printable
	 * page. VI. currentPage is checked to see if this is a new page to render.
	 * If so, pageStartY and pageEndY are reset. VII. To match the coordinates
	 * of the printable clip of graphics2D and the allocation rectangle which
	 * will be used to lay out the views, graphics2D is translated to begin at
	 * the printable X and Y coordinates of the graphics clip. VIII. An
	 * allocation Rectangle is created to represent the layout of the Views.
	 * 
	 * The Printable Interface always prints the area indexed by reference to
	 * the Graphics object. For instance, with a standard 8.5 x 11 inch page
	 * with 1 inch margins the rectangle X = 72, Y = 72, Width = 468, and Height =
	 * 648, the area 72, 72, 468, 648 will be painted regardless of which page
	 * is actually being printed.
	 * 
	 * To align the allocation Rectangle with the graphics2D object two things
	 * are done. The first step is to translate the X and Y coordinates of the
	 * graphics2D object to begin at the X and Y coordinates of the printable
	 * clip, see step VII. Next, when printing other than the first page, the
	 * allocation rectangle must start laying out in coordinates represented by
	 * negative numbers. After page one, the beginning of the allocation is
	 * started at minus the page end of the prior page. This moves the part
	 * which has already been rendered to before the printable clip of the
	 * graphics2D object.
	 * 
	 * X. The printView method is called to paint the page. Its return value
	 * will indicate if a page has been rendered.
	 * 
	 * Although public, print should not ordinarily be called by programs other
	 * than PrinterJob.
	 */
	public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) {
		double scale = 1.0;
		Graphics2D graphics2D;
		View rootView;
		// I
		graphics2D = (Graphics2D) graphics;
		// II
		jeditorPane.setSize((int) pageFormat.getImageableWidth(),
				Integer.MAX_VALUE);
		jeditorPane.validate();
		// III
		rootView = jeditorPane.getUI().getRootView(jeditorPane);
		// IV
		if ((scaleWidthToFit)
				&& (jeditorPane.getMinimumSize().getWidth() > pageFormat
						.getImageableWidth())) {
			scale = pageFormat.getImageableWidth()
					/ jeditorPane.getMinimumSize().getWidth();
			graphics2D.scale(scale, scale);
		}
		// V
		graphics2D.setClip((int) (pageFormat.getImageableX() / scale),
				(int) (pageFormat.getImageableY() / scale), (int) (pageFormat
						.getImageableWidth() / scale), (int) (pageFormat
						.getImageableHeight() / scale));
		// VI
		if (pageIndex > currentPage) {
			currentPage = pageIndex;
			pageStartY += pageEndY;
			pageEndY = graphics2D.getClipBounds().getHeight();
		}
		// VII
		graphics2D.translate(graphics2D.getClipBounds().getX(), graphics2D
				.getClipBounds().getY());
		// VIII
		Rectangle allocation = new Rectangle(0, (int) -pageStartY,
				(int) (jeditorPane.getMinimumSize().getWidth()),
				(int) (jeditorPane.getPreferredSize().getHeight()));
		// X
		if (printView(graphics2D, allocation, rootView)) {
			return Printable.PAGE_EXISTS;
		} else {
			pageStartY = 0;
			pageEndY = 0;
			currentPage = -1;
			return Printable.NO_SUCH_PAGE;
		}
	}

	/*
	 * print(HTMLDocument) is called to set an HTMLDocument for printing.
	 */
	public void print(HTMLDocument htmlDocument) {
		setDocument(htmlDocument);
		printDialog();
	}

	/*
	 * print(JEditorPane) prints a Document contained within a JEDitorPane.
	 */
	public void print(JEditorPane jedPane) {
		setDocument(jedPane);
		printDialog();
	}

	/*
	 * print(PlainDocument) is called to set a PlainDocument for printing.
	 */
	public void print(PlainDocument plainDocument) {
		setDocument(plainDocument);
		printDialog();
	}

	/*
	 * A protected method, printDialog(), displays the print dialog and
	 * initiates printing in response to user input.
	 */
	protected void printDialog() {
		if (pJob.printDialog()) {
			pJob.setPrintable(this, pFormat);
			try {
				pJob.print();
			} catch (PrinterException printerException) {
				pageStartY = 0;
				pageEndY = 0;
				currentPage = -1;
				System.out.println("Error Printing Document");
			}
		}
	}

	/*
	 * printView is a recursive method which iterates through the tree structure
	 * of the view sent to it. If the view sent to printView is a branch view,
	 * that is one with children, the method calls itself on each of these
	 * children. If the view is a leaf view, that is a view without children
	 * which represents an actual piece of text to be painted, printView
	 * attempts to render the view to the Graphics2D object.
	 * 
	 * I. When any view starts after the beginning of the current printable
	 * page, this means that there are pages to print and the method sets
	 * pageExists to true. II. When a leaf view is taller than the printable
	 * area of a page, it cannot, of course, be broken down to fit a single
	 * page. Such a View will be printed whenever it intersects with the
	 * Graphics2D clip. III. If a leaf view intersects the printable area of the
	 * graphics clip and fits vertically within the printable area, it will be
	 * rendered. IV. If a leaf view does not exceed the printable area of a page
	 * but does not fit vertically within the Graphics2D clip of the current
	 * page, the method records that this page should end at the start of the
	 * view. This information is stored in pageEndY.
	 */
	protected boolean printView(Graphics2D graphics2D, Shape allocation,
			View view) {
		boolean pageExists = false;
		Rectangle clipRectangle = graphics2D.getClipBounds();
		Shape childAllocation;
		View childView;

		if (view.getViewCount() > 0) {
			for (int i = 0; i < view.getViewCount(); i++) {
				childAllocation = view.getChildAllocation(i, allocation);
				if (childAllocation != null) {
					childView = view.getView(i);
					if (printView(graphics2D, childAllocation, childView)) {
						pageExists = true;
					}
				}
			}
		} else {
			// I
			if (allocation.getBounds().getMaxY() >= clipRectangle.getY()) {
				pageExists = true;
				// II
				if ((allocation.getBounds().getHeight() > clipRectangle
						.getHeight())
						&& (allocation.intersects(clipRectangle))) {
					view.paint(graphics2D, allocation);
				} else {
					// III
					if (allocation.getBounds().getY() >= clipRectangle.getY()) {
						if (allocation.getBounds().getMaxY() <= clipRectangle
								.getMaxY()) {
							view.paint(graphics2D, allocation);
						} else {
							// IV
							if (allocation.getBounds().getY() < pageEndY) {
								pageEndY = allocation.getBounds().getY();
							}
						}
					}
				}
			}
		}
		return pageExists;
	}

	/*
	 * Method to set the content type the JEditorPane.
	 */
	protected void setContentType(String type) {
		jeditorPane.setContentType(type);
	}

	/*
	 * Method to set an HTMLDocument as the Document to print.
	 */
	public void setDocument(HTMLDocument htmlDocument) {
		jeditorPane = new JEditorPane();
		setDocument("text/html", htmlDocument);
	}

	/*
	 * Method to set the Document to print as the one contained in a
	 * JEditorPane. This method is useful when Java does not provide direct
	 * access to a particular Document type, such as a Rich Text Format
	 * document. With this method such a document can be sent to the
	 * DocumentRenderer class enclosed in a JEditorPane.
	 */
	public void setDocument(JEditorPane jedPane) {
		jeditorPane = new JEditorPane();
		setDocument(jedPane.getContentType(), jedPane.getDocument());
	}

	/*
	 * Method to set a PlainDocument as the Document to print.
	 */
	public void setDocument(PlainDocument plainDocument) {
		jeditorPane = new JEditorPane();
		setDocument("text/plain", plainDocument);
	}

	/*
	 * Method to set the content type and document of the JEditorPane.
	 */
	protected void setDocument(String type, Document document) {
		setContentType(type);
		jeditorPane.setDocument(document);
	}

	/*
	 * Method to set the current choice of the width scaling option.
	 */
	public void setScaleWidthToFit(boolean scaleWidth) {
		scaleWidthToFit = scaleWidth;
	}
}
```

Und aufgerufen wird es beispielsweise so:

```
PageFormat pageFormat = new PageFormat();
			Paper a4paper = new Paper();
			double paperWidth = 8.26;
			double paperHeight = 11.69;
			a4paper.setSize(paperWidth * 72.0, paperHeight * 72.0);

			/*
			 * set the margins respectively the imageable area
			 */
			double leftMargin = 0.78; /* should be about 2cm */
			double rightMargin = 0.78;
			double topMargin = 0.78;
			double bottomMargin = 0.78;

			a4paper.setImageableArea(leftMargin * 72.0, topMargin * 72.0,
					(paperWidth - leftMargin - rightMargin) * 72.0, (paperHeight
							- topMargin - bottomMargin) * 72.0);
			pageFormat.setPaper(a4paper);
			//pageFormat.setOrientation(PageFormat.LANDSCAPE);

			DocumentRenderer documentRenderer = new DocumentRenderer(pageFormat,
					"Report");
			documentRenderer.print(textPane);
```

Hier wird beispielsweise ein in einer JTextPane dargestelltes HTML-Dokument ausgedruckt. Da lässt sich sicher auch der Dialog irgenwo abstellen. Das sollte über die printDialog()-Methode (pJob.printDialog()) gehen. Ob das bei der Desktop-Klasse auch geht weiß ich nicht.

Viele Grüße!

P.S.: Was beim DocumentRenderer allerdings wiederum nicht so gut funktioniert: Linien von Tabellen und Aufzählungszeichen werden seltsamerweise nicht gedruckt. Drucken in Java ist halt immer so eine Sache.


----------

