/*
Copyright 2007-2010 Stefano Chizzolini. http://www.pdfclown.org
Contributors:
* Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it)
This file should be part of the source code distribution of "PDF Clown library"
(the Program): see the accompanying README files for more info.
This Program is free software; you can redistribute it and/or modify it under the terms
of the GNU Lesser General Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later version.
This Program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY,
either expressed or implied; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.
You should have received a copy of the GNU Lesser General Public License along with this
Program (see README files); if not, go to the GNU website (http://www.gnu.org/licenses/).
Redistribution and use, with or without modification, are permitted provided that such
redistributions retain the above copyright notice, license and disclaimer, along with
this list of conditions.
*/
package org.pdfclown.tools;
import org.pdfclown.documents.Page;
import org.pdfclown.documents.contents.Contents;
import org.pdfclown.documents.contents.ContentScanner;
import org.pdfclown.documents.contents.composition.PrimitiveComposer;
import org.pdfclown.documents.contents.objects.RestoreGraphicsState;
import org.pdfclown.documents.contents.objects.SaveGraphicsState;
import org.pdfclown.files.File;
import org.pdfclown.objects.PdfArray;
import org.pdfclown.objects.PdfDataObject;
import org.pdfclown.objects.PdfDirectObject;
import org.pdfclown.objects.PdfName;
import org.pdfclown.objects.PdfReference;
import org.pdfclown.objects.PdfStream;
/**
Tool for content insertion into existing pages.
@author Stefano Chizzolini (http://www.stefanochizzolini.it)
@version 0.1.0
*/
public final class PageStamper
{
// <class>
// <dynamic>
// <fields>
private Page page;
private PrimitiveComposer background;
private PrimitiveComposer foreground;
// </fields>
// <constructors>
public PageStamper(
)
{this(null);}
public PageStamper(
Page page
)
{setPage(page);}
// </constructors>
// <interface>
// <public>
public void flush(
)
{
// Ensuring that there's room for the new content chunks inside the page's content stream...
/*
NOTE: This specialized stamper is optimized for content insertion without modifying
existing content representations, leveraging the peculiar feature of page structures
to express their content streams as arrays of data streams.
*/
PdfArray streams;
{
PdfDirectObject contentsObject = page.getBaseDataObject().get(PdfName.Contents);
PdfDataObject contentsDataObject = File.resolve(contentsObject);
// Single data stream?
if(contentsDataObject instanceof PdfStream)
{
/*
NOTE: Content stream MUST be expressed as an array of data streams in order to host
background- and foreground-stamped contents.
*/
streams = new PdfArray();
streams.add(contentsObject);
page.getBaseDataObject().put(PdfName.Contents,streams);
page.update(); // Fundamental to override original page contents collection.
}
else
{
streams = (PdfArray)contentsDataObject;
if(!File.update(contentsObject))
{page.update();} // Fundamental to override original page contents collection.
}
}
// Background.
// Serialize the content!
background.flush();
// Insert the serialized content into the page's content stream!
streams.add(
0,
(PdfReference)background.getScanner().getContents().getBaseObject()
);
// Foreground.
// Serialize the content!
foreground.flush();
// Append the serialized content into the page's content stream!
streams.add(
(PdfReference)foreground.getScanner().getContents().getBaseObject()
);
}
public PrimitiveComposer getBackground(
)
{return background;}
public PrimitiveComposer getForeground(
)
{return foreground;}
public Page getPage(
)
{return page;}
public void setPage(
Page value
)
{
page = value;
if(page == null)
{
background = null;
foreground = null;
}
else
{
// Background.
background = createFilter();
// Open the background local state!
background.add(SaveGraphicsState.Value);
// Close the background local state!
background.add(RestoreGraphicsState.Value);
// Open the middleground local state!
background.add(SaveGraphicsState.Value);
// Move into the background!
background.getScanner().move(1);
// Foregrond.
foreground = createFilter();
// Close the middleground local state!
foreground.add(RestoreGraphicsState.Value);
}
}
// </public>
// <private>
private PrimitiveComposer createFilter(
)
{
PdfReference reference = page.getFile().register(new PdfStream());
return new PrimitiveComposer(
new ContentScanner(
new Contents(
reference,
reference.getIndirectObject(),
page
)
)
);
}
// </private>
// </interface>
// </dynamic>
// </class>
}