radkovo / CSSBoxPdf

PDF renderer for the CSSBox rendering engine.
GNU Lesser General Public License v3.0
6 stars 9 forks source link

Guess font name and attribute from file nam is not correct, especially for CJK fonts. #6

Open chunlinyao opened 4 years ago

chunlinyao commented 4 years ago

CSSBoxPdf guess font file url by matching file name and font family name. It's not correct especially for CJK font. I suggest using FontMapper to get font.

Change PDFRender#setFont like this. It is still a POC.

    /**
     * Creates object describing font
     * 
     * @return the font object
     */
    private PDFont setFont(String fontFamily, boolean isItalic, boolean isBold)
    {
        COSDictionary dictionary = new COSDictionary();
        dictionary.setItem( COSName.TYPE, COSName.FONT_DESC );
        PDFontDescriptor desc = new PDFontDescriptor(dictionary);
        desc.setItalic(isItalic);
        desc.setFontWeight(isBold? 700: 400);
        desc.setFontFamily(fontFamily);
        FontMapping<TrueTypeFont> trueTypeFont = FontMappers.instance().getTrueTypeFont(fontFamily, desc);

        PDFont font = null;
        if (trueTypeFont != null) {
            try {
                font = PDType0Font.load(doc, trueTypeFont.getFont(), true);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return font;
    }
chunlinyao commented 4 years ago

POC commit.

https://github.com/chunlinyao/CSSBoxPdf/commit/3730044aa2c5c48cc89a573c860bf71ff73701e8

radkovo commented 4 years ago

Thanks for submitting this, it look much better than the original solution (which was very old). I am really interested in including it in the project.

radkovo commented 4 years ago

Well, I did some more testing and it seems to me that this method is not able to find the bold and italic variants. E.g. for Arial it ends up with ArialMT in all cases independently on the isBold and isItalic arguments. I dived a bit into the getTrueTypeFont() code and it seems that descriptor is generally ignored for the common fonts and otherwise, the code is full of font name-based heuristics similarly to my original code. Or am I missing something?

radkovo commented 4 years ago

For your info, my current version that seems to work at least with the common fonts:

    private PDFont createFont(String fontFamily, boolean isItalic, boolean isBold)
    {
        //guess a postscript name
        String psname = fontFamily.replace(" ", "");
        if (isBold && isItalic) psname += ",BoldItalic";
        else if (isBold) psname += ",Bold";
        else if (isItalic) psname += ",Italic";
        //font descriptor is used only for finding fallback fonts when the mapping fails
        COSDictionary dictionary = new COSDictionary();
        dictionary.setItem(COSName.TYPE, COSName.FONT_DESC);
        PDFontDescriptor desc = new PDFontDescriptor(dictionary);
        desc.setItalic(isItalic);
        desc.setFontWeight(isBold ? 700 : 400);
        desc.setFontFamily(fontFamily);
        FontMapping<TrueTypeFont> trueTypeFont = FontMappers.instance().getTrueTypeFont(psname, desc);

        PDFont font = null;
        if (trueTypeFont != null) {
            try {
                font = PDType0Font.load(doc, trueTypeFont.getFont(), true);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return font;
    }
chunlinyao commented 4 years ago

It seems work well, Maybe allow user provide additional font substitute table will be more flexible.

Radek Burget notifications@github.com 于 2019年11月20日周三 上午3:58写道:

For your info, my current version that seems to work at least with the common fonts:

private PDFont createFont(String fontFamily, boolean isItalic, boolean isBold)
{
    //guess a postscript name
    String psname = fontFamily.replace(" ", "");
    if (isBold && isItalic) psname += ",BoldItalic";
    else if (isBold) psname += ",Bold";
    else if (isItalic) psname += ",Italic";
    //font descriptor is used only for finding fallback fonts when the mapping fails
    COSDictionary dictionary = new COSDictionary();
    dictionary.setItem(COSName.TYPE, COSName.FONT_DESC);
    PDFontDescriptor desc = new PDFontDescriptor(dictionary);
    desc.setItalic(isItalic);
    desc.setFontWeight(isBold ? 400 : 700);
    desc.setFontFamily(fontFamily);
    FontMapping<TrueTypeFont> trueTypeFont = FontMappers.instance().getTrueTypeFont(psname, desc);

    PDFont font = null;
    if (trueTypeFont != null) {
        try {
            font = PDType0Font.load(doc, trueTypeFont.getFont(), true);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    return font;
}

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/radkovo/CSSBoxPdf/issues/6?email_source=notifications&email_token=AABEJNZ2HGWLACYYU6XM2U3QURAPXA5CNFSM4JNYXE32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEEPRD3I#issuecomment-555684333, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABEJN2U2VJDX3WBXFGLBFDQURAPXANCNFSM4JNYXE3Q .