For WPdfImage and WPdfRenderer users... difference from #2 codepage

Added by Henry Morgan 6 months ago

Hello

jwt supplied with 4.75 pdfjet library. It's ok unless you're trying to create pdf with chars different from codepage 2 i.e. english. After reading manual you're goint to try use addFontCollection. But you have no chance.
Take a look at static initializer in WPdfImage line 42:


for (Constructor c : Font.class.getConstructors()) {
Class[] paramTypes = c.getParameterTypes();
if (paramTypes.length == 4 &&

So we are looking for constructors with 4 parameters. But, unfortunately, it doesn't exist. Even in v6 of pdfjet. You may use v6 with 3 args (without embed) but you have to solve some problems with font namings (CoreFont)


Replies (9)

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 6 months ago

It seems that that constructor is indeed missing. Maybe it broke when updating to another version of PDFJet or something. That's something we'll have to fix.

We'll also consider upgrading to the latest open source version of PDFJet (6.05) in a next release.

Regards,
Roel

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 5 months ago

Ah, I see that the commit that added that mentioned that the commercial version of PDFJet (I guess 4.75 back then) was necessary for that. There does seem to be a constructor that takes three args including an InputStream in the latest open source version.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 5 months ago

Hm, looks like at the time that was written PDFJet 3.03 was still being used.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 5 months ago

I took a look at the latest commercial version of PDFJet vs the latest open source version, and it seems that the commercial version still has this constructor we're looking for. It looks like the open source version simply does not allow font embedding, sorry.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Henry Morgan 5 months ago

Frankly speaking i don't see any problems with using external fonts and free version of pdfjet. My quick fix for WPdfImage was:

1. Fix constructor

....
import com.pdfjet.CoreFont;
....
static {
    for (Constructor< ? > c : Font.class.getConstructors()) {
        Class< ? >[] paramTypes = c.getParameterTypes();
        if (paramTypes.length == 3 &&
            paramTypes[0] == PDF.class &&
            paramTypes[1] == java.io.InputStream.class &&
            //paramTypes[2].isPrimitive() && paramTypes[2].equals(java.lang.Integer.TYPE) &&
            paramTypes[2].isPrimitive() && paramTypes[2].equals(java.lang.Boolean.TYPE)) {
            fontConstructor = c;
            break;
        }
    }
}

2. Fix createFont - loading font file as stream and use CoreFont enum font constructor

private Font createFont(WFont font) {
    if (fontConstructor != null) {
        FontMatch fm = trueTypeFonts.matchFont(font);
        if (fm.isMatched()) {
            try {
                FileInputStream fis = new FileInputStream(fm.getFileName()); //<------------------------ check this
                //Font f = (Font)fontConstructor.newInstance(pdf, fis, CodePage.UNICODE, Embed.YES);
                Font f = (Font)fontConstructor.newInstance(pdf, fis, Embed.YES); //<------------------------ and this
                f.setSize(font.getSizeLength().toPixels());
                return f;
            }
            catch (IllegalArgumentException e) {
                logger.error("IllegalArgumentException while creating font {}", font.getCssText(), e);
            }
            catch (InstantiationException e) {
                logger.error("InstantiationException while creating font {}", font.getCssText(), e);
            }
            catch (IllegalAccessException e) {
                logger.error("IllegalAccessException while creating font {}", font.getCssText(), e);
            }
            catch (InvocationTargetException e) {
                logger.error("InvocationTargetException while creating font {}", font.getCssText(), e);
            }
            catch (FileNotFoundException e) {
                logger.info("FileNotFoundException while creating font {}", font.getCssText(), e);
            }
        }
    }

    String name = PdfUtils.toBase14Font(font);
    try {
        Font f = new Font(pdf, NameToCore(name)); //<------------------ Here
        f.setSize(font.getSizeLength().toPixels());
        return f;
    }
    catch (Exception e) {
        logger.info("Error creating font {}", font.getCssText(), e);
        return null;
    }
}

3. Fix font names - font name conversion from name to CoreFont enum

private CoreFont NameToCore(String sName)
{
    CoreFont oCoreFont = null;

    if ("Helvetica".equals(sName))
    {
        oCoreFont = CoreFont.HELVETICA;
    }
    else
        if ("Times".equals(sName))
        {
            oCoreFont = CoreFont.TIMES_ROMAN;
        }
        else
            if ("Courier".equals(sName))
            {
                oCoreFont = CoreFont.COURIER;
            }
            else
                if ("Symbol".equals(sName))
                {
                    oCoreFont = CoreFont.SYMBOL;
                }
                else
                    if ("ZapfDingbats".equals(sName))
                    {
                        oCoreFont = CoreFont.ZAPF_DINGBATS;
                    }
    return oCoreFont;
}

So, when i specify slyle sheet like

<style type="text/css">* { overflow-wrap:break-word;font-family:DejaVuLGCSans,SansSerif;font-style:normal;font-weight:300;}

WT loads fonts/DejaVuLGCSans.ttf streaming font from classpath. The rendering code is like this:

private void RenderPdf(WString sXhtmlSource, PDF oPdf) throws Exception
{
    Page oPage = new Page(oPdf, A4.PORTRAIT);
    WPdfRenderer renderer = new WPdfRenderer(oPdf, oPage);
    String sPath = null;
    if (IsJboss())
    {
        sPath = ((VirtualFile)(new URL(getClass().getProtectionDomain().getCodeSource().getLocation().toString() + "/fonts")).openConnection().getContent()).getPhysicalFile().getPath();
    }
    else
    {
        sPath = Paths.get(getClass().getClassLoader().getResource("fonts/").toURI()).toString();
    }
    renderer.addFontCollection(sPath);
    renderer.setMargin(2.54);
    renderer.setDpi(96);

    renderer.render(sXhtmlSource);
}

It's rough fix but it works.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Henry Morgan 5 months ago

...sorry for formatting the code. Redmine is a mystery to me that I cannot comprehend.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Henry Morgan 5 months ago

I have attached full file for whom it's badly necessary as was for me.

WPdfImage.java Magnifier (22.5 KB)

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 5 months ago

You can use pre tags with Redmine. If you want to just copy paste some code. I can try to reformat your post.

RE: For WPdfImage and WPdfRenderer users... difference from #2 codepage - Added by Roel Standaert 5 months ago

Yeah, maybe we could fallback to that.

It would be nicer to just have font embedding, but that would require us to switch to something else.

(1-9/9)