You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-dev@xmlgraphics.apache.org by Craig Ringer <cr...@postnewspapers.com.au> on 2011/12/16 09:14:28 UTC

Document and page callbacks for image handlers

Hi

I'm interested in implementing merging of duplicate subset fonts in 
Jeremias's fop-pdf-image extension. I'm working with fop 1.0, and i'm 
having trouble with two things:

- A clean way to associate data that's private to the image processing 
plugin with a particular rendering run so I can access it across 
multiple invocations of the plugin; and

- How to append some additional PDF objects after the last page is 
emitted but before the PDF document trailer and final xref table(s) are 
written out.

I think I've figured out how to associate private image plugin data with 
the document being rendered (using the RenderContext as a key to a 
static WeakHashMap in the plugin) but it seems like a pretty ugly 
approach, so I'm hoping there's a better way I'm missing.

More problematic is that I need to emit additional PDF objects after the 
last page - or at least the last image - has been rendered. I can't see 
any obivous callbacks to fop image plugins to notify them when a new 
document is started, a new page started, a page finished or a new 
document finished. Fop seems to have an event system but it seems to be 
oriented toward trapping error conditions and problems rather than doing 
extra work at certain processing phases. In particular, PDFEventProducer 
doesn't seem to be useful for this.

Any advice on how to hook document completion after the last page is 
written but before the pdf trailer and other closing pdf structure are 
written, so I can write out some indirect objects I've only written 
indirect references to so far?

Sorry if these are somewhat stupid questions. I'm very new to fop's 
codebase and I'm still getting my head around it.

--
Craig Ringer

POST Newspapers
276 Onslow Rd, Shenton Park
Ph: 08 9381 3088     Fax: 08 9388 2258
ABN: 50 008 917 717
http://www.postnewspapers.com.au/

Re: Document and page callbacks for image handlers

Posted by Craig Ringer <ri...@ringerc.id.au>.
On 21/12/2011 5:07 PM, Chris Bowditch wrote:

> FOP can't currently fully embed a font in PDF, so even if you had the 
> source font available the code changes required could be extensive. 
> For us, this approach isn't an option because we don't have the source 
> font to register in fop.xconf and embed. Therefore I am interested in 
> knowing what you've come up with in terms of merging subsets together 
> to create 1 super subset. That in my view is the most difficult 
> challenge in this problem. Resolving the problems with the cross 
> references and the point at which IDs are assigned should be solvable 
> with a little code refactoring. I'm sure one of the guys will speak up 
> if that's not the case.

As yet I haven't begun to tackle the actual merging of Type 1 or 
TrueType subsets into a single font. I've done the accumulation and 
merging of the widths arrays, but not the fonts themselves. I plan to 
make new minimum subsets from local fonts if they're available, and will 
try merging of actual embedded font files only if I can't get that to 
work or if I have time. I don't know font data structures well enough to 
want to try merging subset embedded font files if I can possibly avoid it.

I've just finished writing and testing the code to accumulate 
information on each font as its encountered in a source PDF and merge it 
into a collection of font information keyed by 
(FontName,SubType,Encoding). I compare the metrics to ensure that the 
fonts are really compatible and if they are I merge the widths arrays 
and startchar/endchar to produce information. At the end of the run I 
can now produce a font dictionary and font descriptor for the minimum 
subset required to satisfy the requirements of each of the embedded 
documents using that font.

I can report on font usage, glyph usage within each font, and potential 
size savings, but I don't yet have it actually replacing the fonts. 
That's what I'll be working on today. First I'll be trying to use fop's 
font embedding mechanism to do it, which will require adding some 
callbacks to fop's pdf output to run code just before the resource 
dictionary is written out so I can inform fop of the required glyphs. 
I'll be delaying the writing of all the xobject resource dictionaries 
until after the fop resource dictionary is written so I know the fop 
font oids and can embed them in the xobject resource dictionaries. With 
luck I'm hoping I'll be able to write the minimum subset but I haven't 
looked into fop's font embedding code in enough detail to be sure 
exactly what I can do or how, so I'll be going delving shortly.

If this approach works the next step will be to allocate font object IDs 
early so I don't need to waste memory on delaying xobject resource 
dictionary writes and so I can avoid writing keys for fonts fop its self 
never uses to fop's resource dictionary.

Yesterday I attempted to unembed base-14 fonts during import of PDF 
content, so I'd recognise fonts like Helvetica in type1 and replace them 
with a font dictionary for a base14 font reference rather than the embed 
dictionary. Acrobat choked on the result for reasons I'm not entirely 
sure of as it looked OK structurally. I'm not sure quite what was wrong, 
but hope to have more luck with re-embedding rather than replacement 
with a base-14 font.

On a side note, I also need to enhance the font info collection code so 
it keys on more of the font metrics. Currently the first font with a 
given (FontName,SubType,Encoding) tuple is registered for that key, and 
if subsequent fonts with the same key but incompatible metrics are 
encountered they're copied over verbatim exactly as is currently the 
case. Expanding the key to cover the font bbox, ascent and descent etc 
will help solve that and won't be hard, I'm just leaving it until I have 
a proof of concept font re-embed working.

--
Craig Ringer

Re: Document and page callbacks for image handlers

Posted by Chris Bowditch <bo...@hotmail.com>.
On 19/12/2011 07:20, Craig Ringer wrote:

Hi Craig,

Thanks for the detailed e-mail. This is indeed an interesting topic. As 
I mentioned in an earlier e-mail this is something that we've recently 
been working on too.

>> - A clean way to associate data that's private to the image 
>> processing plugin with a particular rendering run so I can access it 
>> across multiple invocations of the plugin; and
>
> For anyone else who needs this later: There doesn't appear to be any 
> especially nice way to do this with FOP's current image handler API, 
> as there's no general-purpose map on the user agent for image handlers 
> to stash their data in and nothing like that is passed as a param to 
> the image handler calls. The hints mechanism can pass data from a 
> preloader to a loader for the same image, but it can't be used to pass 
> data between image loaders.
>
> What I've landed up doing is keying a WeakHashMap off the FOUserAgent 
> for the rendering run, as obtained via the RenderingContext passed to 
> ImageHandler.handleImage(...). So long as lookups and insertions on 
> the WeakHashMap are synchronized this is safe and will release the 
> image handler's per-render information when the FOUserAgent is 
> discarded at the end of the rendering run.
>
> I'm now able to accumulate font usage information from the PDFs I 
> examine as I embed them and build a list of which fonts are used. I 
> can combine width arrays and first/last char listings to determine 
> which glyphs are required if the font is to be embedded as a subset.

In our situation we had several large PDFs of around 50 pages each. What 
happens in this case is that the plug-in uses PDF Box to split the PDF 
into 50 separate PDFs which results in the same font being duplicated 50 
times. We have solved this particular problem by altering the way the 
cache works in the plug-in. However, this doesn't solve the wider 
problem of fonts repeated in different input PDFs. Mehdi developed the 
code and will be able to provide a patch after the holiday season.

>
>>
>> - How to append some additional PDF objects after the last page is 
>> emitted but before the PDF document trailer and final xref table(s) 
>> are written out.
>
> For anyone else looking at this now or later:
>
> It's possible to allocate a PDFObject and request that it be written 
> out at the end of the document. PDFDocument.outputTrailer(...) writes 
> objects added to the trailer list. Those objects were allocated via 
> the factory where they were given an object ID, but were then passed 
> to addTrailerObject(...) to request that they be written out at the 
> end of document production. If I ever start producing my own combined 
> font subsets from the original subset fonts in the input PDFs, this is 
> probably how I'd insert the combined font subset object.
>
> If I'm restricting font combining to fonts where fop has an original 
> font file and using fop's font subsystem the above would require too 
> much duplication and make it hard to avoid embedding fonts twice (once 
> for form xobjects, once for main content). Instead I need to mark a 
> font as used in fop's FontInfo for the rendering run so fop writes it 
> out, and I need to obtain the font object's PDF object ID so I can 
> write forward references to it in the XObject forms' resource 
> dictionaries.
>
> The problem here is that fop doesn't assign fonts an object ID until 
> very late in writing. The first reference to font objects is from the 
> resource dictionary, and fop only writes one of those - it is shared 
> between all pages and written out just before the trailer. Since fonts 
> are written out with the resources dictionary and don't usually need 
> object IDs until the resources dictionary has to reference them 
> there's no way to get their object IDs earlier in PDF production. This 
> changes when we need to write private resource dictionaries for 
> embedded form xobjects.
>
> I'm looking at forcing early embedding of fonts with direct 
> makeFont(...) calls. This'll work so long as I'm happy embedding whole 
> fonts, but will prevent fop from subsetting the font for its own use 
> and prevent me from subsetting it for xobject forms.
>
> Alternately, I could defer the writing of the xobject form resource 
> dictionaries till the end of the document so I didn't need to know the 
> font object IDs early - but I'd still need a way to write them *after* 
> the main fop resource dictionary. If I wanted to subset then I'd also 
> need a hook for just before fonts were written out by fop to adjust 
> the glyph width tables. I don't see any way around this without some 
> kind of PDF renderer listener for image handlers etc to use.
>
> I'll try to put together a proof of concept that embeds whole fonts if 
> the font is found in a pdf form xobject, de-duplicating references so 
> all pdf form xobjects that use that font reference the same one. Fop 
> will use the same font since it knows about it and has stored it in 
> the used fonts map, so the only problem is that the whole font is 
> embedded rather than a subset.

FOP can't currently fully embed a font in PDF, so even if you had the 
source font available the code changes required could be extensive. For 
us, this approach isn't an option because we don't have the source font 
to register in fop.xconf and embed. Therefore I am interested in knowing 
what you've come up with in terms of merging subsets together to create 
1 super subset. That in my view is the most difficult challenge in this 
problem. Resolving the problems with the cross references and the point 
at which IDs are assigned should be solvable with a little code 
refactoring. I'm sure one of the guys will speak up if that's not the case.

>
> Anyone working on the same thing, please feel free to drop me a note.

Thanks,

Chris

>
> -- 
> Craig Ringer
>
>


Re: Document and page callbacks for image handlers

Posted by Craig Ringer <ri...@ringerc.id.au>.
> - A clean way to associate data that's private to the image processing 
> plugin with a particular rendering run so I can access it across 
> multiple invocations of the plugin; and

For anyone else who needs this later: There doesn't appear to be any 
especially nice way to do this with FOP's current image handler API, as 
there's no general-purpose map on the user agent for image handlers to 
stash their data in and nothing like that is passed as a param to the 
image handler calls. The hints mechanism can pass data from a preloader 
to a loader for the same image, but it can't be used to pass data 
between image loaders.

What I've landed up doing is keying a WeakHashMap off the FOUserAgent 
for the rendering run, as obtained via the RenderingContext passed to 
ImageHandler.handleImage(...). So long as lookups and insertions on the 
WeakHashMap are synchronized this is safe and will release the image 
handler's per-render information when the FOUserAgent is discarded at 
the end of the rendering run.

I'm now able to accumulate font usage information from the PDFs I 
examine as I embed them and build a list of which fonts are used. I can 
combine width arrays and first/last char listings to determine which 
glyphs are required if the font is to be embedded as a subset.

>
> - How to append some additional PDF objects after the last page is 
> emitted but before the PDF document trailer and final xref table(s) 
> are written out.

For anyone else looking at this now or later:

It's possible to allocate a PDFObject and request that it be written out 
at the end of the document. PDFDocument.outputTrailer(...) writes 
objects added to the trailer list. Those objects were allocated via the 
factory where they were given an object ID, but were then passed to 
addTrailerObject(...) to request that they be written out at the end of 
document production. If I ever start producing my own combined font 
subsets from the original subset fonts in the input PDFs, this is 
probably how I'd insert the combined font subset object.

If I'm restricting font combining to fonts where fop has an original 
font file and using fop's font subsystem the above would require too 
much duplication and make it hard to avoid embedding fonts twice (once 
for form xobjects, once for main content). Instead I need to mark a font 
as used in fop's FontInfo for the rendering run so fop writes it out, 
and I need to obtain the font object's PDF object ID so I can write 
forward references to it in the XObject forms' resource dictionaries.

The problem here is that fop doesn't assign fonts an object ID until 
very late in writing. The first reference to font objects is from the 
resource dictionary, and fop only writes one of those - it is shared 
between all pages and written out just before the trailer. Since fonts 
are written out with the resources dictionary and don't usually need 
object IDs until the resources dictionary has to reference them there's 
no way to get their object IDs earlier in PDF production. This changes 
when we need to write private resource dictionaries for embedded form 
xobjects.

I'm looking at forcing early embedding of fonts with direct 
makeFont(...) calls. This'll work so long as I'm happy embedding whole 
fonts, but will prevent fop from subsetting the font for its own use and 
prevent me from subsetting it for xobject forms.

Alternately, I could defer the writing of the xobject form resource 
dictionaries till the end of the document so I didn't need to know the 
font object IDs early - but I'd still need a way to write them *after* 
the main fop resource dictionary. If I wanted to subset then I'd also 
need a hook for just before fonts were written out by fop to adjust the 
glyph width tables. I don't see any way around this without some kind of 
PDF renderer listener for image handlers etc to use.

I'll try to put together a proof of concept that embeds whole fonts if 
the font is found in a pdf form xobject, de-duplicating references so 
all pdf form xobjects that use that font reference the same one. Fop 
will use the same font since it knows about it and has stored it in the 
used fonts map, so the only problem is that the whole font is embedded 
rather than a subset.

Anyone working on the same thing, please feel free to drop me a note.

--
Craig Ringer