OK, I've gotten in over my head at last I think. This is what I have so far - it's clearly calling the code, but I get tiny (1.1k) pdf with nothing in it to speak of. I don't even pretend to understand PDF; I'm just trying to make do with gum and duct tape here.
Warning: ugly code. I added a class, OnTheFlyFopImage, did various bad things to FopImageFactory so that I can plug them in and use them, and am stuck trying to get good output from PDFRenderer - I think I might be having coordinate space/AffineTransform or just plain PDF formatting problems. I dunno, you tell me. I could probably cobble this together as a patch to 0.20.3 and put up a test case if anyone wanted to actually compile it; I was hoping that someone would just spot the mistake though. It's certainly fast :-) **************************************** First, my OnTheFlyFopImage. As you can see, it does almost nothing other than store the width and height and provide an abstract paint(Graphics2D g) method for subclasses. package org.apache.fop.image; import org.apache.fop.datatypes.ColorSpace; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFFilter; import java.awt.Graphics2D; public abstract class OnTheFlyFopImage implements FopImage { private String url; private ColorSpace colorSpace; private int height; private int width; public OnTheFlyFopImage(String url, int width, int height) throws FopImageException { this.url = url; this.width = width; this.height = height; colorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); } public boolean invertImage() { return false; } public String getURL() { return url; } // image size public int getWidth() throws FopImageException { return width; } public int getHeight() throws FopImageException { return height; } public ColorSpace getColorSpace() throws FopImageException { return colorSpace; } public int getBitsPerPixel() throws FopImageException { return 24; } public boolean isTransparent() throws FopImageException { return false; } public PDFColor getTransparentColor() throws FopImageException { return new PDFColor(0.0, 0.0, 0.0); } // get the image bytes, and bytes properties // get uncompressed image bytes public byte[] getBitmaps() throws FopImageException { return null; } // width * (bitsPerPixel / 8) * height, no ? public int getBitmapsSize() throws FopImageException { return 0; } // get compressed image bytes // I don't know if we really need it, nor if it // should be changed... public byte[] getRessourceBytes() throws FopImageException { return null; } public int getRessourceBytesSize() throws FopImageException { return 0; } // return null if no corresponding PDFFilter public PDFFilter getPDFFilter() throws FopImageException { return null; } // release memory public void close() { } // ******** subclass homework public abstract void paint(Graphics2D graphics); } **************************************** Here are the relevant parts of PDFRenderer that I modified. I changed renderImageArea to pass through OnTheFlyFopImages to my new renderOnTheFlyFopImage subroutine. The latter does the actual production, or rather lack thereof. /** * render image area to PDF * * @param area the image area to render */ public void renderImageArea(ImageArea area) { // adapted from contribution by BoBoGi int x = this.currentXPosition + area.getXOffset(); int y = this.currentYPosition; int w = area.getContentWidth(); int h = area.getHeight(); this.currentYPosition -= h; FopImage img = area.getImage(); if (img instanceof SVGImage) { try { closeText(); SVGDocument svg = ((SVGImage)img).getSVGDocument(); currentStream.add("ET\nq\n"); renderSVGDocument(svg, (int)x, (int)y, area.getFontState()); currentStream.add("Q\nBT\n"); } catch (FopImageException e) {} } else if (img instanceof OnTheFlyFopImage) { // try { closeText(); // currentStream.add("ET\nq\n"); renderOnTheFlyFopImage((OnTheFlyFopImage)img, x, y, area.getFontState()); // currentStream.add("Q\nBT\n"); // } catch (FopImageException e) {} } else { int xObjectNum = this.pdfDoc.addImage(img); closeText(); currentStream.add("ET\nq\n" + (((float)w) / 1000f) + " 0 0 " + (((float)h) / 1000f) + " " + (((float)x) / 1000f) + " " + (((float)(y - h)) / 1000f) + " cm\n" + "/Im" + xObjectNum + " Do\nQ\nBT\n"); } this.currentXPosition += area.getContentWidth(); } /** * I copied and butchered this from renderSVGDocument. I took out * everything that seemed SVG-specific. It runs, and does indeed * use the graphics object, but nothing comes out in the final. */ protected void renderOnTheFlyFopImage(OnTheFlyFopImage image, int x, int y, FontState fs) { System.out.println("Rendering on-the-fly graphic to pdf."); try { // ******** mysterious stuff here float sx = 1, sy = -1; int xOffset = x, yOffset = y; // get the 'width' and 'height' attributes of the image float w = (float)image.getWidth() * 1000f; float h = (float)image.getHeight() * 1000f; currentStream.add("q\n"); if (w != 0 && h != 0) { currentStream.add(x / 1000f + " " + y / 1000f + " m\n"); currentStream.add((x + w) / 1000f + " " + y / 1000f + " l\n"); currentStream.add((x + w) / 1000f + " " + (y - h) / 1000f + " l\n"); currentStream.add(x / 1000f + " " + (y - h) / 1000f + " l\n"); currentStream.add("h\n"); currentStream.add("W\n"); currentStream.add("n\n"); } // transform so that the coordinates (0,0) is from the top left // and positive is down and to the right. (0,0) is where the // viewBox puts it. currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " " + yOffset / 1000f + " cm\n"); // do the actual paint PDFGraphics2D graphics = new PDFGraphics2D(true, fs, pdfDoc, currentFontName, currentFontSize, currentXPosition, currentYPosition); graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); image.paint(graphics); // more mystery currentStream.add(graphics.getString()); currentAnnotList = graphics.getAnnotList(); currentStream.add("Q\n"); } catch (Exception oopsie) { oopsie.printStackTrace(System.err); } } -- Paul Reavis [EMAIL PROTECTED] Design Lead Partner Software, Inc. http://www.partnersoft.com --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]