Ответы пользователя по тегу PDF
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Попробуйте во этот проект: Create PDFs in your browser (port of libharu)
    Ответ написан
    Комментировать
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Вот, например, в pdfjs (для node.js), добавление шрифта в документ:

    pdfjs

    Функция TTFFont.Subset.prototype.embed строка 1065.
    Со строки 1099 - 1143. // unicode map
    И т.д.
    Ответ написан
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Вот здест Unicode in PDF, пишут
    See Appendix D (page 995) of the PDF specification. There is a limited number of fonts and
    character sets pre-defined in a PDF consumer application. To display other characters you 
    need to embed a font that contains them. It is also preferable to embed only a subset of 
    the font, including only required characters, in order to reduce file size. 
    I am also working on displaying Unicode characters in PDF and it is a major hassle.
    adobe.com/devnet/pdf/pdf_reference.html
    .
    Нету в стандартных шрифтах кириллицы.
    В jsPDF нет средств внедрения шрифтов.
    Например, mPDF (PHP), так и поступает, внедряет подмножество шрифта.
    Т. е. "просмоторщик" pdf должен сам содержать/предоставлять юникодные шрифты.
    Предположим наш "просмоторщик" такие шрифты даёт.

    Добавьте в файл jspdf.js перед строкой 1912 (return API; функция jsPDF) код
    var padz = 
    [
       "",
       "0",
       "00",
       "000",
       "0000"
    ];
    var pdfEscape16 = function(text, flags) 
    {
       var ar = ["FEFF"];
       for(var i = 0, l = text.length, t; i < l; ++i)
       {
          t = text.charCodeAt(i).toString(16).toUpperCase();
          ar.push(padz[4 - t.length], t);
       }
       return ar.join("");
    };
    
    API.text16 = function (text, x, y, flags) 
    {
       /**
       * Inserts something like this into PDF
       BT
       /F1 16 Tf % Font name + size
       16 TL % How many units down for next line in multiline text
       0 g % color
       28.35 813.54 Td % position
       (line one) Tj
       T* (line two) Tj
       T* (line three) Tj
       ET
       */
    
       var undef, _first, _second, _third, newtext, str, i;
       // Pre-August-2012 the order of arguments was function(x, y, text, flags)
       // in effort to make all calls have similar signature like
       // function(data, coordinates... , miscellaneous)
       // this method had its args flipped.
       // code below allows backward compatibility with old arg order.
       if (typeof text === 'number') {
           _first = y;
           _second = text;
           _third = x;
    
           text = _first;
           x = _second;
           y = _third;
       }
    
       // If there are any newlines in text, we assume
       // the user wanted to print multiple lines, so break the
       // text up into an array. If the text is already an array,
       // we assume the user knows what they are doing.
       if (typeof text === 'string' && text.match(/[\n\r]/)) {
           text = text.split(/\r\n|\r|\n/g);
       }
    
       if (typeof flags === 'undefined') {
           flags = {'noBOM': true, 'autoencode': true};
       } else {
    
           if (flags.noBOM === undef) {
               flags.noBOM = true;
           }
    
           if (flags.autoencode === undef) {
               flags.autoencode = true;
           }
    
       }
    
       if (typeof text === 'string') {
           str = pdfEscape16(text, flags);
       } else if (text instanceof Array) { /* Array */
           // we don't want to destroy original text array, so cloning it
           newtext = text.concat();
           // we do array.join('text that must not be PDFescaped")
           // thus, pdfEscape each component separately
           for (i = newtext.length - 1; i !== -1; i--) {
               newtext[i] = pdfEscape16(newtext[i], flags);
           }
           str = newtext.join("> Tj\nT* <");
       } else {
           throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
       }
       // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
    
       // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
       // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
       // Thus, there is NO useful, *reliable* concept of "default" font for a page.
       // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
       // - readers dealing smartly with brokenness of jsPDF's markup.
       out(
           'BT\n/' +
               activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
               (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
               textColor +
               '\n' + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' Td\n<' +
               str +
               '> Tj\nET'
       );
       
       return this;
    };

    Добавлять текст через вызов функции text16.
    Ответ написан
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Точно, смотрел старую версию...
    Смотрим git, прямо по коду

    Строка 1149: API.text = function (text, x, y, flags) {
    Параметр flags

    Строка 1202: str = pdfEscape(text, flags);
    Функция pdfEscape

    Строка 801: pdfEscape = function (text, flags) {
    Параметр flags

    Строка 811: return to8bitStream(text, flags)
    Функция to8bitStream

    Строка 659: to8bitStream = function (text, flags) {
    Параметр flags

    Строка 660-707: Комментарий про юникод.

    /* PDF 1.3 spec:
    "For text strings encoded in Unicode, the first two bytes must be 254 followed by
    255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
    with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
    to be a meaningful beginning of a word or phrase.) The remainder of the
    string consists of Unicode character codes, according to the UTF-16 encoding
    specified in the Unicode standard, version 2.0. Commonly used Unicode values
    are represented as 2 bytes per character, with the high-order byte appearing first
    in the string."
    
    In other words, if there are chars in a string with char code above 255, we
    recode the string to UCS2 BE - string doubles in length and BOM is prepended.
    
    HOWEVER!
    Actual *content* (body) text (as opposed to strings used in document properties etc)
    does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
    
    Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
    a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
    fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
    code page. There, however, all characters in the stream are treated as GIDs,
    including BOM, which is the reason we need to skip BOM in content text (i.e. that
    that is tied to a font).
    
    To signal this "special" PDFEscape / to8bitStream handling mode,
    API.text() function sets (unless you overwrite it with manual values
    given to API.text(.., flags) )
    flags.autoencode = true
    flags.noBOM = true
    
    */
    
     /*
    `flags` properties relied upon:
    .sourceEncoding = string with encoding label.
    "Unicode" by default. = encoding of the incoming text.
    pass some non-existing encoding name
    (ex: 'Do not touch my strings! I know what I am doing.')
    to make encoding code skip the encoding step.
    .outputEncoding = Either valid PDF encoding name
    (must be supported by jsPDF font metrics, otherwise no encoding)
    or a JS object, where key = sourceCharCode, value = outputCharCode
    missing keys will be treated as: sourceCharCode === outputCharCode
    .noBOM
    See comment higher above for explanation for why this is important
    .autoencode
    See comment higher above for explanation for why this is important
    */


    Пока всё что разобрал, посмотрю ещё...
    Ответ написан
    Комментировать
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Вот, есть аналогичный вопрос на RSDN:
    Вывод Unicode текста в PDF.
    Ответ написан
    Комментировать
  • Как заставить jsPDF.js корректно создавать PDF с кириллическими символами?

    max7
    @max7
    max7
    Если я правильно понял, что за jsPDF имеется в виду. То по простому никак. Это связано с вариантами поддержки юникода в pdf и разными версиями pdf. Ведь pdf (до версии 1.4 точно) должен поддерживаться принтерами без установленных на них шрифтов, т.е. они должны быть внедрены в документ. Нюансов очень много. Но.

    Попробуйте добавить в код jsPDF следующие функции:

    Вариант функции pdfEscape
    var padz = 
    [
       "",
       "0",
       "00",
       "000",
       "0000"
    ];
    var pdfEscape16 = function(text) 
    {
       var ar = ["FEFF"];
       for(var i = 0, l = text.length, t; i < l; ++i)
       {
          t = text.charCodeAt(i).toString(16).toUpperCase();
          ar.push(padz[4 - t.length], t);
       }
       return ar.join("");
    };


    В объект в конце добавить функцию
    text16: function(x, y, text) 
    {
       // need page height
       if(pageFontSize != fontSize) 
       {
          out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET');
          pageFontSize = fontSize;
       }
       var str = sprintf('BT %.2f %.2f Td <%s> Tj ET', x * k, (pageHeight - y) * k, pdfEscape16(text));
       out(str);
    }


    и добавлять текст через вызов функции text16.
    Ответ написан