git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194565 13f79535-47bb-0310-9956-ffa450edef68pull/30/head
@@ -7,8 +7,9 @@ | |||
package org.apache.fop.area; | |||
import java.util.ArrayList; | |||
import org.apache.fop.render.Renderer; | |||
import java.util.ArrayList; | |||
/** | |||
* Area tree for formatting objects. | |||
@@ -32,8 +33,8 @@ public class AreaTree { | |||
// in different situations | |||
AreaTreeModel model; | |||
public void createRenderPageModel(PageRenderListener listener) { | |||
public RenderPagesModel createRenderPagesModel(Renderer rend) { | |||
return new RenderPagesModel(rend); | |||
} | |||
public static StorePagesModel createStorePagesModel() { | |||
@@ -44,7 +45,7 @@ public class AreaTree { | |||
model = m; | |||
} | |||
public void startPageSequence(Area title) { | |||
public void startPageSequence(Title title) { | |||
model.startPageSequence(title); | |||
} | |||
@@ -54,7 +55,7 @@ public class AreaTree { | |||
// this is the model for the area tree object | |||
public static abstract class AreaTreeModel { | |||
public abstract void startPageSequence(Area title); | |||
public abstract void startPageSequence(Title title); | |||
public abstract void addPage(PageViewport page); | |||
} | |||
@@ -67,7 +68,7 @@ public class AreaTree { | |||
public StorePagesModel() {} | |||
public void startPageSequence(Area title) { | |||
public void startPageSequence(Title title) { | |||
titles.add(title); | |||
if (pageSequence == null) { | |||
pageSequence = new ArrayList(); | |||
@@ -99,18 +100,31 @@ public class AreaTree { | |||
} | |||
} | |||
// this queues pages and will call the render listener | |||
// when the page is ready to be rendered | |||
// if the render supports out of order rendering | |||
// then a ready page is rendered immediately | |||
// this uses the store pages model to store the pages | |||
// each page is either rendered if ready or prepared | |||
// for later rendering | |||
public static class RenderPagesModel extends StorePagesModel { | |||
public void startPageSequence(Area title) {} | |||
public void addPage(PageViewport page) {} | |||
} | |||
Renderer renderer; | |||
ArrayList prepared = new ArrayList(); | |||
public RenderPagesModel(Renderer rend) { | |||
renderer = rend; | |||
} | |||
public void startPageSequence(Title title) { | |||
super.startPageSequence(title); | |||
renderer.startPageSequence(title); | |||
} | |||
public static abstract class PageRenderListener { | |||
public abstract void renderPage(RenderPagesModel model, | |||
int pageseq, int count); | |||
public void addPage(PageViewport page) { | |||
super.addPage(page); | |||
// if page finished | |||
//renderer.renderPage(page); | |||
page.clear(); | |||
// else prepare | |||
//renderer.preparePage(page); | |||
prepared.add(page); | |||
} | |||
} | |||
} |
@@ -54,4 +54,13 @@ public class PageViewport { | |||
public void loadPage(ObjectInputStream in) throws Exception { | |||
page = (Page) in.readObject(); | |||
} | |||
/** | |||
* Clear the page contents to save memory. | |||
* THis objects is kept for the life of the area tree since | |||
* it holds id information and is used as a key. | |||
*/ | |||
public void clear() { | |||
page = null; | |||
} | |||
} |
@@ -21,15 +21,13 @@ import org.apache.fop.render.pdf.CIDFont; | |||
import org.apache.fop.render.pdf.fonts.LazyFont; | |||
import org.apache.fop.datatypes.IDReferences; | |||
import org.apache.fop.layout.Page; | |||
import org.apache.fop.layout.FontMetric; | |||
import org.apache.fop.layout.FontDescriptor; | |||
// Java | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.Hashtable; | |||
import java.util.Enumeration; | |||
import java.util.HashMap; | |||
import java.awt.Rectangle; | |||
/** | |||
@@ -147,7 +145,7 @@ public class PDFDocument { | |||
* the XObjects Map. | |||
* Should be modified (works only for image subtype) | |||
*/ | |||
protected Hashtable xObjectsMap = new Hashtable(); | |||
protected HashMap xObjectsMap = new HashMap(); | |||
/** | |||
* the objects themselves | |||
@@ -936,48 +934,27 @@ public class PDFDocument { | |||
* | |||
* @return the created /Page object | |||
*/ | |||
public PDFPage makePage(PDFResources resources, PDFStream contents, | |||
public PDFPage makePage(PDFResources resources, | |||
int pagewidth, int pageheight) { | |||
/* | |||
* create a PDFPage with the next object number, the given | |||
* resources, contents and dimensions | |||
*/ | |||
PDFPage page = new PDFPage(++this.objectcount, resources, contents, | |||
PDFPage page = new PDFPage(++this.objectcount, resources, | |||
pagewidth, pageheight); | |||
if(pendingLinks != null) { | |||
for(int count = 0; count < pendingLinks.size(); count++) { | |||
PendingLink pl = (PendingLink)pendingLinks.get(count); | |||
PDFGoTo gt = new PDFGoTo(++this.objectcount, | |||
page.referencePDF()); | |||
gt.setDestination(pl.dest); | |||
addTrailerObject(gt); | |||
PDFInternalLink internalLink = | |||
new PDFInternalLink(gt.referencePDF()); | |||
pl.link.setAction(internalLink); | |||
} | |||
pendingLinks = null; | |||
} | |||
/* | |||
if (currentPage != null) { | |||
Enumeration enum = currentPage.getIDList().elements(); | |||
while (enum.hasMoreElements()) { | |||
String id = enum.nextElement().toString(); | |||
idReferences.setInternalGoToPageReference(id, | |||
page.referencePDF()); | |||
} | |||
} | |||
*/ | |||
/* add it to the list of objects */ | |||
this.objects.add(page); | |||
/* add the page to the Root */ | |||
this.root.addPage(page); | |||
return page; | |||
} | |||
public void addPage(PDFPage page) { | |||
/* add it to the list of objects */ | |||
this.objects.add(page); | |||
} | |||
/** | |||
* make a link object | |||
* |
@@ -7,9 +7,8 @@ | |||
package org.apache.fop.pdf; | |||
// Java | |||
import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import java.util.Date; | |||
import java.text.SimpleDateFormat; | |||
/** | |||
* class representing an /Info object | |||
@@ -21,6 +20,15 @@ public class PDFInfo extends PDFObject { | |||
*/ | |||
protected String producer; | |||
protected String title = null; | |||
protected String author = null; | |||
protected String subject = null; | |||
protected String keywords = null; | |||
// the name of the application that created the | |||
// original document before converting to PDF | |||
protected String creator; | |||
/** | |||
* create an Info object | |||
* | |||
@@ -39,6 +47,22 @@ public class PDFInfo extends PDFObject { | |||
this.producer = producer; | |||
} | |||
public void setTitle(String t) { | |||
this.title = t; | |||
} | |||
public void setAuthor(String a) { | |||
this.author = a; | |||
} | |||
public void setSubject(String s) { | |||
this.subject = s; | |||
} | |||
public void setKeywords(String k) { | |||
this.keywords = k; | |||
} | |||
/** | |||
* produce the PDF representation of the object | |||
* | |||
@@ -46,9 +70,29 @@ public class PDFInfo extends PDFObject { | |||
*/ | |||
public byte[] toPDF() { | |||
String p = this.number + " " + this.generation | |||
+ " obj\n<< /Type /Info\n/Producer (" + this.producer | |||
+ ") >>\nendobj\n"; | |||
+ " obj\n<< /Type /Info\n"; | |||
if(title != null) { | |||
p += "/Title (" + this.title + ")\n"; | |||
} | |||
if(author != null) { | |||
p += "/Author (" + this.author + ")\n"; | |||
} | |||
if(subject != null) { | |||
p += "/Subject (" + this.subject + ")\n"; | |||
} | |||
if(keywords != null) { | |||
p += "/Keywords (" + this.keywords + ")\n"; | |||
} | |||
p += "/Producer (" + this.producer + ")\n"; | |||
// creation date in form (D:YYYYMMDDHHmmSSOHH'mm') | |||
Date date = new Date(); | |||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss"); | |||
String str = sdf.format(date) + "+00'00'"; | |||
p += "/CreationDate (D:" + str + ")"; | |||
p += " >>\nendobj\n"; | |||
return p.getBytes(); | |||
} | |||
} | |||
@@ -77,6 +77,37 @@ public class PDFPage extends PDFObject { | |||
this.annotList = null; | |||
} | |||
/** | |||
* create a /Page object | |||
* | |||
* @param number the object's number | |||
* @param resources the /Resources object | |||
* @param pagewidth the page's width in points | |||
* @param pageheight the page's height in points | |||
*/ | |||
public PDFPage(int number, PDFResources resources, | |||
int pagewidth, int pageheight) { | |||
/* generic creation of object */ | |||
super(number); | |||
/* set fields using parameters */ | |||
this.resources = resources; | |||
this.pagewidth = pagewidth; | |||
this.pageheight = pageheight; | |||
this.annotList = null; | |||
} | |||
/** | |||
* set this page contents | |||
* | |||
* @param contents the contents of the page | |||
*/ | |||
public void setContents(PDFStream contents) { | |||
this.contents = contents; | |||
} | |||
/** | |||
* set this page's parent | |||
* |
@@ -119,24 +119,6 @@ public class PDFXObject extends PDFObject { | |||
} | |||
byte[] toPDF() { | |||
/* | |||
* Not used any more | |||
* String p = this.number + " " + this.generation + " obj\n"; | |||
* p = p + "<</Type /XObject\n"; | |||
* p = p + "/Subtype /Image\n"; | |||
* p = p + "/Name /Im"+Xnum+"\n"; | |||
* p = p + "/Width "+fopimage.getpixelwidth()+"\n"; | |||
* p = p + "/Height "+fopimage.getpixelheight()+"\n"; | |||
* p = p + "/BitsPerComponent 8\n"; | |||
* if (fopimage.getcolor()) | |||
* p = p + "/ColorSpace /DeviceRGB\n"; | |||
* else | |||
* p = p + "/ColorSpace /DeviceGray\n"; | |||
* p = p + "/Filter /ASCIIHexDecode\n"; | |||
* p = p + "/Length "; | |||
* return p; | |||
*/ | |||
return null; | |||
} | |||
} |
@@ -58,6 +58,27 @@ public abstract class AbstractRenderer implements Renderer { | |||
options = opt; | |||
} | |||
/** | |||
* Check if this renderer supports out of order rendering. | |||
* If this renderer supports out of order rendering then it | |||
* means that the pages that are not ready will be prepared | |||
* and a future page will be rendered. | |||
*/ | |||
public boolean supportsOutOfOrder() { | |||
return false; | |||
} | |||
/** | |||
* Prepare a page for rendering. | |||
* This is called if the renderer supports out of order rendering. | |||
* The renderer should prepare the page so that a page further on | |||
* in the set of pages can be rendered. The body of the page should | |||
* not be rendered. The page will be rendered at a later time | |||
* by the call to render page. | |||
*/ | |||
public void preparePage(PageViewport page) { | |||
} | |||
/** | |||
* Utility method to convert a page sequence title to a string. | |||
* Some renderers may only be able to use a string title. |
@@ -61,6 +61,10 @@ public interface Renderer { | |||
*/ | |||
public void setProducer(String producer); | |||
public boolean supportsOutOfOrder(); | |||
public void preparePage(PageViewport page); | |||
public void startPageSequence(Title seqTitle); | |||
public void renderPage(PageViewport page) throws IOException, FOPException; |
@@ -28,15 +28,15 @@ import org.w3c.dom.Document; | |||
// Java | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.awt.geom.Rectangle2D; | |||
import java.util.HashMap; | |||
/* | |||
TODO: | |||
viewport clipping | |||
word rendering and optimistion | |||
pdf state optimistation | |||
pdf state optimisation | |||
line and border | |||
leader | |||
background pattern | |||
@@ -58,6 +58,16 @@ public class PDFRenderer extends PrintRenderer { | |||
*/ | |||
protected PDFDocument pdfDoc; | |||
// map of pages using the PageViewport as the key | |||
// this is used for prepared pages that cannot be immediately | |||
// rendered | |||
protected HashMap pages = null; | |||
// page references are stored using the PageViewport as the key | |||
// when a reference is made the PageViewport is used | |||
// for pdf this means we need the pdf page reference | |||
protected HashMap pageReferences = new HashMap(); | |||
protected String producer; | |||
protected OutputStream ostream; | |||
@@ -141,16 +151,50 @@ public class PDFRenderer extends PrintRenderer { | |||
ostream = null; | |||
} | |||
public boolean supportsOutOfOrder() { | |||
return true; | |||
} | |||
/** | |||
* The pdf page is prepared by making the page. | |||
* The page is made in the pdf document without any contents | |||
* and then stored to add the contents later. | |||
* The page objects is stored using the area tree PageViewport | |||
* as a key. | |||
*/ | |||
public void preparePage(PageViewport page) { | |||
this.pdfResources = this.pdfDoc.getResources(); | |||
Rectangle2D bounds = page.getViewArea(); | |||
double w = bounds.getWidth(); | |||
double h = bounds.getHeight(); | |||
currentPage = this.pdfDoc.makePage(this.pdfResources, | |||
(int) Math.round(w / 1000), (int) Math.round(h / 1000)); | |||
if(pages == null) { | |||
pages = new HashMap(); | |||
} | |||
pages.put(page, currentPage); | |||
pageReferences.put(page, currentPage.referencePDF()); | |||
} | |||
/** | |||
* This method creates a pdf stream for the current page | |||
* uses it as the contents of a new page. The page is wriiten | |||
* uses it as the contents of a new page. The page is written | |||
* immediately to the output stream. | |||
*/ | |||
public void renderPage(PageViewport page) throws IOException, | |||
FOPException { | |||
this.pdfResources = this.pdfDoc.getResources(); | |||
if(pages != null && (currentPage = (PDFPage)pages.get(page)) != null) { | |||
pages.remove(page); | |||
} else { | |||
this.pdfResources = this.pdfDoc.getResources(); | |||
Rectangle2D bounds = page.getViewArea(); | |||
double w = bounds.getWidth(); | |||
double h = bounds.getHeight(); | |||
currentPage = this.pdfDoc.makePage(this.pdfResources, | |||
(int) Math.round(w / 1000), (int) Math.round(h / 1000)); | |||
pageReferences.put(page, currentPage.referencePDF()); | |||
} | |||
currentStream = this.pdfDoc.makeStream(); | |||
currentStream.add("BT\n"); | |||
@@ -159,15 +203,9 @@ public class PDFRenderer extends PrintRenderer { | |||
currentStream.add("ET\n"); | |||
Rectangle2D bounds = page.getViewArea(); | |||
double w = bounds.getWidth(); | |||
double h = bounds.getHeight(); | |||
currentPage = this.pdfDoc.makePage(this.pdfResources, currentStream, | |||
(int) Math.round(w / 1000), (int) Math.round(h / 1000)); | |||
currentPage.setContents(currentStream); | |||
this.pdfDoc.addPage(currentPage); | |||
this.pdfDoc.output(ostream); | |||
} | |||
} |
@@ -37,6 +37,7 @@ import org.apache.batik.ext.awt.g2d.GraphicContext; | |||
public class PDFDocumentGraphics2D extends PDFGraphics2D { | |||
OutputStream stream; | |||
PDFPage currentPage; | |||
PDFStream pdfStream; | |||
int width; | |||
int height; | |||
@@ -77,6 +78,10 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { | |||
currentFontSize = 0; | |||
currentYPosition = 0; | |||
currentXPosition = 0; | |||
PDFResources pdfResources = this.pdfDoc.getResources(); | |||
currentPage = this.pdfDoc.makePage(pdfResources, | |||
width, height); | |||
} | |||
void setupDocument(OutputStream stream, int width, int height) { | |||
@@ -149,8 +154,8 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { | |||
public void finish() throws IOException { | |||
pdfStream.add(getString()); | |||
PDFResources pdfResources = this.pdfDoc.getResources(); | |||
PDFPage currentPage = this.pdfDoc.makePage(pdfResources, pdfStream, | |||
width, height); | |||
currentPage.setContents(pdfStream); | |||
this.pdfDoc.addPage(currentPage); | |||
if(currentAnnotList != null) { | |||
currentPage.setAnnotList(currentAnnotList); | |||
} |