Project

General

Profile

Bug #8374

PDFJet unicode

Added by Vladimir Savchik 3 months ago. Updated 3 months ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
-
Target version:
-
Start date:
04/16/2021
Due date:
% Done:

0%

Estimated time:

Description

public class WPdfImage extends WResource implements WPaintDevice {
private static final Logger logger = LoggerFactory.getLogger(WPdfImage.class);

private static Constructor<?> fontConstructor;  

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

PDFJet Font has no such constructor at all.
As a result custom font collection does not work:
private Font createFont(WFont font) {
if (fontConstructor != null) {
FontMatch fm = trueTypeFonts.matchFont(font);

#1

Updated by Korneel Dumon 3 months ago

Hi,

can you provide a code example that illustrates the problem?

#2

Updated by Vladimir Savchik 3 months ago

Korneel Dumon wrote in #note-1:

Hi,

can you provide a code example that illustrates the problem?

@Override
protected void handleRequest( WebRequest request , WebResponse response) throws IOException {
    response.setContentType( "application/pdf" );

    try {
        PDF pdf = new PDF( response.getOutputStream() );            
        renderReport( pdf );

    Page page = new Page( pdf , A4.PORTRAIT );
    WPdfRenderer renderer = new WPdfRenderer( pdf , page );
    ActionBase action = view.main.getAction();
    renderer.addFontCollection( action.getLocalPath( Common.getPath( action.execrc.installPath , "fonts" ) ) );
    renderer.setMargin( 2.54 );
    renderer.setDpi( 96 );

    String filePath = action.getWorkFilePath( "pdf.html" );
    Common.createFileFromString( action.execrc , filePath , html );
    action.trace( "pdf html copied to " + filePath );
    renderer.render( html );

...

full at http://usvn.ahuman.org/svn/urmweb/trunk/src/org/urm/web/view/system/ReleaseNotesPDF.java

practically I forced jwt working by changing your code here:
private Font createFont(WFont font) {
/*
if (fontConstructor != null) {
FontMatch fm = trueTypeFonts.matchFont(font);
if (fm.isMatched()) {
try {
FileInputStream fis = new FileInputStream(fm.getFileName());
Font f = (Font)fontConstructor.newInstance(pdf, fis, CodePage.UNICODE, Embed.YES);
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);
}
}
}
*/
FontMatch fm = trueTypeFonts.matchFont(font);
if (fm.isMatched()) {
try {
FileInputStream fis = new FileInputStream(fm.getFileName());
Font f = new Font(pdf, fis, Font.STREAM);
f.setSize(font.getSizeLength().toPixels());
return f;
} catch (Exception e) {
logger.info("Exception while creating font {}", font.getCssText(), e);
}
}

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

btw, added code to split long strings w/o whitespace, e.g. urls
@Override
public WTextItem measureText(CharSequence text, double maxWidth, boolean wordWrap) {
processChangeFlags();

    if (wordWrap) {
        if (maxWidth == -1) {
            return new WTextItem(text, font.stringWidth(text.toString()));
        } else {
            String previousWord = null;
            double previousWordWidth = 0;

            int len = text.length();            
            for (int i = 0; i < len; ++i) {
                double w;
                if (Character.isWhitespace(text.charAt(i)))
                    w = font.stringWidth(text.subSequence(0, i).toString());
                else if (i == len - 1)
                    w = font.stringWidth(text.subSequence(0, i + 1).toString());
                else
                    continue;

                String s = text.subSequence(0, i + 1).toString();

                if (w > maxWidth) {
                    if (previousWord == null)
                        return measureTextExact(text, maxWidth);
                        /*return new WTextItem(s, w);*/
                    else
                        return new WTextItem(previousWord, previousWordWidth);
                } else {
                    previousWord = s;
                    previousWordWidth = w;
                }
            }
            return new WTextItem(text, font.stringWidth(text.toString()));
        }
    } else {
        return new WTextItem(text, font.stringWidth(text.toString()));
    }
}

private WTextItem measureTextExact(CharSequence text, double maxWidth) {
    int len = text.length();            
    double width = 0;
    for (int i = 0; i < len; ++i) {
        double w = font.stringWidth(text.subSequence(0, i + 1).toString());
        if (w > maxWidth)
            return new WTextItem(text.subSequence(0, i).toString(), width);
        width = w;
    }
    return new WTextItem(text, width);
}
#3

Updated by Vladimir Savchik 3 months ago

Problem finally - that default font is chosen, which has no cyrillic chars, and pdf is garbage there.

#4

Updated by Roel Standaert 3 months ago

I believe this is a limitation of the open source version of PDFJet. I think it simply does not support font embedding.

#5

Updated by Vladimir Savchik 3 months ago

Roel Standaert wrote in #note-4:

I believe this is a limitation of the open source version of PDFJet. I think it simply does not support font embedding.

maybe, but

  1. Trial version from PDFJet site does not contain 4-args constructor.
  2. I believe font matching and font embedding are different features.
#6

Updated by Roel Standaert 3 months ago

Yeah, things may have changed in the meantime. I think you still needed the font embedding feature (or just TTF font support) in PDFJet in order to actually do proper font matching, which was not in the open source version.

Also available in: Atom PDF