package org.apache.fop.render.ps;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.ps.DSCConstants;
import org.apache.xmlgraphics.ps.PSGenerator;
import org.apache.xmlgraphics.ps.PSResource;
import org.apache.xmlgraphics.ps.dsc.DSCException;
import org.apache.xmlgraphics.ps.dsc.DSCFilter;
import org.apache.xmlgraphics.ps.dsc.DSCListener;
import org.apache.xmlgraphics.ps.dsc.DSCParser;
import org.apache.xmlgraphics.ps.dsc.DSCParserConstants;
import org.apache.xmlgraphics.ps.dsc.DefaultNestedDocumentHandler;
import org.apache.xmlgraphics.ps.dsc.ResourceTracker;
import org.apache.xmlgraphics.ps.dsc.events.DSCComment;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentNeededResources;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentSuppliedResources;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentIncludeResource;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentLanguageLevel;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage;
import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages;
import org.apache.xmlgraphics.ps.dsc.events.DSCEvent;
import org.apache.xmlgraphics.ps.dsc.events.DSCHeaderComment;
import org.apache.xmlgraphics.ps.dsc.events.PostScriptComment;
import org.apache.xmlgraphics.ps.dsc.events.PostScriptLine;
import org.apache.xmlgraphics.ps.dsc.tools.DSCTools;
import org.apache.fop.ResourceEventProducer;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerRegistry;
public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors {
private static Log log = LogFactory.getLog(ResourceHandler.class);
private FOUserAgent userAgent;
private FontInfo fontInfo;
private PSEventProducer eventProducer;
private ResourceTracker resTracker;
private Map globalFormResources = new java.util.HashMap();
private Map inlineFormResources = new java.util.HashMap();
public ResourceHandler(FOUserAgent userAgent, PSEventProducer eventProducer,
FontInfo fontInfo, ResourceTracker resTracker, Map formResources) {
this.userAgent = userAgent;
this.eventProducer = eventProducer;
this.fontInfo = fontInfo;
this.resTracker = resTracker;
determineInlineForms(formResources);
}
private void determineInlineForms(Map formResources) {
if (formResources == null) {
return;
}
for (Object o : formResources.entrySet()) {
Map.Entry entry = (Map.Entry) o;
PSResource res = (PSResource) entry.getValue();
long count = resTracker.getUsageCount(res);
if (count > 1) {
this.globalFormResources.put(entry.getKey(), res);
} else {
this.inlineFormResources.put(res, res);
resTracker.declareInlined(res);
}
}
}
public void process(InputStream in, OutputStream out,
int pageCount, Rectangle2D documentBoundingBox, PSRenderingUtil psUtil)
throws DSCException, IOException {
DSCParser parser = new DSCParser(in);
parser.setCheckEOF(false);
PSGenerator gen = new PSGenerator(out);
gen.setAcrobatDownsample(psUtil.isAcrobatDownsample());
parser.addListener(new DefaultNestedDocumentHandler(gen));
parser.addListener(new IncludeResourceListener(gen));
DSCHeaderComment header = DSCTools.checkAndSkipDSC30Header(parser);
header.generate(gen);
parser.setFilter(new DSCFilter() {
private final Set filtered = new java.util.HashSet();
{
filtered.add(DSCConstants.PAGES);
filtered.add(DSCConstants.BBOX);
filtered.add(DSCConstants.HIRES_BBOX);
filtered.add(DSCConstants.DOCUMENT_NEEDED_RESOURCES);
filtered.add(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES);
}
public boolean accept(DSCEvent event) {
if (event.isDSCComment()) {
return !(filtered.contains(event.asDSCComment().getName()));
} else {
return true;
}
}
});
while (true) {
DSCEvent event = parser.nextEvent();
if (event == null) {
reportInvalidDSC();
}
if (DSCTools.headerCommentsEndHere(event)) {
DSCCommentPages pages = new DSCCommentPages(pageCount);
pages.generate(gen);
new DSCCommentBoundingBox(documentBoundingBox).generate(gen);
new DSCCommentHiResBoundingBox(documentBoundingBox).generate(gen);
PSFontUtils.determineSuppliedFonts(resTracker, fontInfo, fontInfo.getUsedFonts());
registerSuppliedForms(resTracker, globalFormResources);
DSCCommentDocumentSuppliedResources supplied
= new DSCCommentDocumentSuppliedResources(
resTracker.getDocumentSuppliedResources());
supplied.generate(gen);
DSCCommentDocumentNeededResources needed
= new DSCCommentDocumentNeededResources(
resTracker.getDocumentNeededResources());
needed.generate(gen);
event.generate(gen);
break;
}
if (event.isDSCComment()) {
DSCComment comment = event.asDSCComment();
if (DSCConstants.LANGUAGE_LEVEL.equals(comment.getName())) {
DSCCommentLanguageLevel level = (DSCCommentLanguageLevel)comment;
gen.setPSLevel(level.getLanguageLevel());
}
}
event.generate(gen);
}
PostScriptComment fontSetupPlaceholder = parser.nextPSComment("FOPFontSetup", gen);
if (fontSetupPlaceholder == null) {
throw new DSCException("Didn't find %FOPFontSetup comment in stream");
}
PSFontUtils.writeFontDict(gen, fontInfo, fontInfo.getUsedFonts(), eventProducer);
generateForms(globalFormResources, gen);
DSCComment pageOrTrailer = parser.nextDSCComment(DSCConstants.PAGE, gen);
if (pageOrTrailer == null) {
throw new DSCException("Page expected, but none found");
}
while (true) {
DSCCommentPage page = (DSCCommentPage)pageOrTrailer;
page.generate(gen);
pageOrTrailer = DSCTools.nextPageOrTrailer(parser, gen);
if (pageOrTrailer == null) {
reportInvalidDSC();
} else if (!DSCConstants.PAGE.equals(pageOrTrailer.getName())) {
pageOrTrailer.generate(gen);
break;
}
}
while (parser.hasNext()) {
DSCEvent event = parser.nextEvent();
event.generate(gen);
}
gen.flush();
}
private static void reportInvalidDSC() throws DSCException {
throw new DSCException("File is not DSC-compliant: Unexpected end of file");
}
private static void registerSuppliedForms(ResourceTracker resTracker, Map formResources)
throws IOException {
if (formResources == null) {
return;
}
for (Object o : formResources.values()) {
PSImageFormResource form = (PSImageFormResource) o;
resTracker.registerSuppliedResource(form);
}
}
private void generateForms(Map formResources, PSGenerator gen) throws IOException {
if (formResources == null) {
return;
}
for (Object o : formResources.values()) {
PSImageFormResource form = (PSImageFormResource) o;
generateFormForImage(gen, form);
}
}
private void generateFormForImage(PSGenerator gen, PSImageFormResource form)
throws IOException {
final String uri = form.getImageURI();
ImageManager manager = userAgent.getImageManager();
ImageInfo info = null;
try {
ImageSessionContext sessionContext = userAgent.getImageSessionContext();
info = manager.getImageInfo(uri, sessionContext);
PSRenderingContext formContext = new PSRenderingContext(
userAgent, gen, fontInfo, true);
ImageFlavor[] flavors;
ImageHandlerRegistry imageHandlerRegistry
= userAgent.getImageHandlerRegistry();
flavors = imageHandlerRegistry.getSupportedFlavors(formContext);
Map hints = ImageUtil.getDefaultHints(sessionContext);
org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
info, flavors, hints, sessionContext);
ImageHandler basicHandler = imageHandlerRegistry.getHandler(formContext, img);
if (basicHandler == null) {
throw new UnsupportedOperationException(
"No ImageHandler available for image: "
+ img.getInfo() + " (" + img.getClass().getName() + ")");
}
if (!(basicHandler instanceof PSImageHandler)) {
throw new IllegalStateException(
"ImageHandler implementation doesn't behave properly."
+ " It should have returned false in isCompatible(). Class: "
+ basicHandler.getClass().getName());
}
PSImageHandler handler = (PSImageHandler)basicHandler;
if (log.isTraceEnabled()) {
log.trace("Using ImageHandler: " + handler.getClass().getName());
}
handler.generateForm(formContext, img, form);
} catch (ImageException ie) {
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
userAgent.getEventBroadcaster());
eventProducer.imageError(resTracker, (info != null ? info.toString() : uri),
ie, null);
}
}
private class IncludeResourceListener implements DSCListener {
private PSGenerator gen;
public IncludeResourceListener(PSGenerator gen) {
this.gen = gen;
}
public void processEvent(DSCEvent event, DSCParser parser)
throws IOException, DSCException {
if (event.isDSCComment() && event instanceof DSCCommentIncludeResource) {
DSCCommentIncludeResource include = (DSCCommentIncludeResource)event;
PSResource res = include.getResource();
if (res.getType().equals(PSResource.TYPE_FORM)) {
if (inlineFormResources.containsValue(res)) {
PSImageFormResource form = (PSImageFormResource)
inlineFormResources.get(res);
gen.writeln("save");
generateFormForImage(gen, form);
boolean execformFound = false;
DSCEvent next = parser.nextEvent();
if (next.isLine()) {
PostScriptLine line = next.asLine();
if (line.getLine().endsWith(" execform")) {
line.generate(gen);
execformFound = true;
}
}
if (!execformFound) {
throw new IOException(
"Expected a PostScript line in the form: <form> execform");
}
gen.writeln("restore");
} else {
}
parser.next();
}
}
}
}
}