iTextSharp 5 польский персонаж - PullRequest
6 голосов
/ 04 февраля 2011

У меня проблема с польским символом, использующим itextSharp. Я хочу создать PDF из HTML. Все отлично работает, но польский характер отсутствует. Я использую функцию ниже:

    private void createPDF(string html)
    {
        //MemoryStream msOutput = new MemoryStream();
        TextReader reader = new StringReader(html);// step 1: creation of a document-object
        Document document = new Document(PageSize.A4, 30, 30, 30, 30);

        // step 2:
        // we create a writer that listens to the document
        // and directs a XML-stream to a file
        PdfWriter writer = PdfWriter.GetInstance(document, new FileStream("Test.pdf", FileMode.Create));

        // step 3: we create a worker parse the document
        HTMLWorker worker = new HTMLWorker(document);

        // step 4: we open document and start the worker on the document
        document.Open();
        worker.StartDocument();

        // step 5: parse the html into the document
        worker.Parse(reader);

        // step 6: close the document and the worker
        worker.EndDocument();
        worker.Close();
        document.Close();
    }

И попробуйте использовать его:

CreatePDF ( "ĄąćęĘłŁŃńóÓŚśŹźŻż");

Я пытаюсь установить:

BaseFont bf = BaseFont.CreateFont (BaseFont.TIMES_ROMAN, Encoding.UTF8.HeaderName, BaseFont.EMBEDDED);

        writer.DirectContent.SetFontAndSize(bf, 16);

Но это не работает

У вас есть идеи ??

Привет

Ответы [ 5 ]

7 голосов
/ 05 января 2012

Я получил ответ! =) (специально предназначено для полировки) Я чувствую себя обязанным поместить это здесь в эту старую ветку, так как я уверен, что не буду последним, кто найдет его.

Я сильно разочарован тем, что нет хороших ответов на этот вопрос ... большинство из них предлагают использовать ARIALUNI.TTF в вашей папке Windows FONTS, в результате чего ваш файл PDF будет во много раз больше. Решение не должно быть таким решительным ...

Многие другие предлагают примеры, показывающие кодировку cp1252, которая не работает в Arial и не работает с Helvetica для польского текста.

Я использую iTextSharp 4.1.6 ... хитрость ... cp1257! И вы можете использовать его с BaseFont.Courier, BaseFont.Helvetica, BaseFont.Times-Roman

Это работает ... и мои PDF-файлы крошечные (3 КБ!)

document.Open();
var bigFont = FontFactory.GetFont(BaseFont.COURIER, BaseFont.CP1257, 18, Font.BOLD);
var para = new Paragraph("Oryginał", bigFont);
document.Add(pgDocType);
document.Close();

Я протестирую позже и убедитесь, что могу открыть и прочитать их в Windows XP и Mac OSX в дополнение к Windows 7.

6 голосов
/ 05 февраля 2011

Просто собрать вместе то, что @Mark Storer сказал:

private void createPDF(string html)
{
    //MemoryStream msOutput = new MemoryStream();
    TextReader reader = new StringReader(html);// step 1: creation of a document-object
    Document document = new Document(PageSize.A4, 30, 30, 30, 30);

    // step 2:
    // we create a writer that listens to the document
    // and directs a XML-stream to a file
    PdfWriter writer = PdfWriter.GetInstance(document, new FileStream("Test.pdf", FileMode.Create));

    // step 3: we create a worker parse the document
    HTMLWorker worker = new HTMLWorker(document);

    // step 4: we open document and start the worker on the document
    document.Open();

    // step 4.1: register a unicode font and assign it an allias
    FontFactory.Register("C:\\Windows\\Fonts\\ARIALUNI.TTF", "arial unicode ms");

    // step 4.2: create a style sheet and set the encoding to Identity-H
    iTextSharp.text.html.simpleparser.StyleSheet ST = New iTextSharp.text.html.simpleparser.StyleSheet();
    ST.LoadTagStyle("body", "encoding", "Identity-H");

    // step 4.3: assign the style sheet to the html parser
    worker.Style = ST;

    worker.StartDocument();

    // step 5: parse the html into the document
    worker.Parse(reader);

    // step 6: close the document and the worker
    worker.EndDocument();
    worker.Close();
    document.Close();
}

И когда вы звоните, оберните текст шрифтом, используя имя, которое вы зарегистрировали выше:

createPDF("<font face=""arial unicode ms"">ĄąćęĘłŁŃńóÓŚśŹźŻż</font>");
2 голосов
/ 05 июля 2014

Просматривая различные форумы и вопросы, связанные со стеком, я не нашел ответа со сложным решением проблемы специальных символов. Я попытался предоставить один в обмен на довольно длинный ответ на вопрос. Надеюсь, это кому-нибудь поможет ...

Я использовал XMLWorker из SourceForge , когда HtmlWorker стал ограниченным. Проблема со спецсимволами осталась задуманной. Я нашел два решения, которые действительно работают и могут использоваться как по отдельности, так и в сочетании.

HTML & CSS решение

Для каждого задействованного тега необходимо указать стиль семейства шрифтов, чтобы правильно интерпретировать его методом ParseXHtml (я не уверен, почему здесь не работает наследование стилей вложенных тегов, но, похоже, это не так или нет не полностью).

Это решение позволяет изменять полученный PDF-файл только на основе HTML-кода, поэтому могут иметь место некоторые сценарии без перекомпиляции кода.

Упрощенный код (для приложения MVC) будет выглядеть так:

Контроллер:

public FileStreamResult GetPdf()
{
    const string CONTENT_TYPE = "application/pdf"
    var fileName = "mySimple.pdf";
    var html = GetViewPageHtmlCode();
    //the way how to capture view HTML are described in other threads, e.g. [here][2]
    var css = Server.MapPath("~/Content/Pdf.css");
    using (var capturedActionStream = new MemoryStream(USED_ENCODING.GetBytes(html)))
    {
        using (var cssFile = new FileStream(css),  FileMode.Open))
        {
            var memoryStream = new MemoryStream();
            //to create landscape, use PageSize.A4.Rotate() for pageSize
            var document = new Document(PageSize.A4, 30, 30, 10, 10);
            var writer = PdfWriter.GetInstance(document, memoryStream);
            var worker = XMLWorkerHelper.GetInstance();

            document.Open();
            worker.ParseXHtml(writer, document, capturedActionStream, cssFile);
            writer.CloseStream = false;
            document.Close();
            memoryStream.Position = 0;

            //to enforce file download
            HttpContext.Response.AddHeader(
                "Content-Disposition",
                String.Format("attachment; filename={0}", fileName));
            var wrappedPdf = new FileStreamResult(memoryStream, CONTENT_TYPE);
            return wrappedPdf;
        }
    }
}

CSS:

body {
    background-color: white;
    font-size: .85em;
    font-family: Arial;
    margin: 0;
    padding: 0;
    color: black;
}

p, ul {
    margin-bottom: 20px;
    line-height: 1.6em;
}

div, span {
    font-family: Arial;
}

h1, h2, h3, h4, h5, h6 {
    font-size: 1.5em;
    color: #000;
    font-family: Arial;
}

Просмотр макета

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        <title>@ViewBag.Title</title>
        <link href="@Url.Content("~/Content/Pdf.css")" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <div class="page">
            <div id="main">
                @RenderBody()
            </div>
        </div>
    </body>
    </html>

Просмотр страницы

@{
    ViewBag.Title = "PDF page title"
}

<h1>@ViewBag.Title</h1>

<p>
    ěščřžýáíéů ĚŠČŘŽÝÁÍÉŮ
</p>

Решение для замены шрифтов внутри кода

В этом решении шрифт, возвращаемый IFontProvider, изменяется на тот, который содержит (правильное) представление специальных символов и используется кодировка BaseFont.IDENTITY_H. Преимущество такого подхода заключается в том, что используется ровно один шрифт. Это также недостаток рода.

Кроме того, в этом решении предполагается, что шрифт является частью проекта (файлы * .ttf, помещенные в папку Content/Fonts).

В качестве альтернативы шрифты могут быть получены из расположения шрифтов Windows: Environment.GetFolderPath(Environment.SpecialFolder.Fonts) - это требует знания (или строгого убеждения) шрифтов, установленных на сервере, или контроля над сервером

FontProvider (свыше FontFactory)

Я позволил себе немного расширить решение Грегора S , которое предоставляет более сложную FontFactory, которую можно использовать для различных HTML-шаблонов, проталкиваемых через XMLWorker.

public class CustomFontFactory : FontFactoryImp
{
    public const Single DEFAULT_FONT_SIZE = 12;
    public const Int32 DEFAULT_FONT_STYLE = 0;
    public static readonly BaseColor DEFAULT_FONT_COLOR = BaseColor.BLACK;

    public String DefaultFontPath { get; private set; }
    public String DefaultFontEncoding { get; private set; }
    public Boolean DefaultFontEmbedding { get; private set; }
    public Single DefaultFontSize { get; private set; }
    public Int32 DefaultFontStyle { get; private set; }
    public BaseColor DefaultFontColor { get; private set; }

    public Boolean ReplaceEncodingWithDefault { get; set; }
    public Boolean ReplaceEmbeddingWithDefault { get; set; }
    public Boolean ReplaceFontWithDefault { get; set; }
    public Boolean ReplaceSizeWithDefault { get; set; }
    public Boolean ReplaceStyleWithDefault { get; set; }
    public Boolean ReplaceColorWithDefault { get; set; }

    public BaseFont DefaultBaseFont { get; protected set; }

    public CustomFontFactory(
        String defaultFontFilePath,
        String defaultFontEncoding = BaseFont.IDENTITY_H,
        Boolean defaultFontEmbedding = BaseFont.EMBEDDED,
        Single? defaultFontSize = null,
        Int32? defaultFontStyle = null,
        BaseColor defaultFontColor = null,
        Boolean automaticalySetReplacementForNullables = true)
    {
        //set default font properties
        DefaultFontPath =  defaultFontFilePath;
        DefaultFontEncoding = defaultFontEncoding;
        DefaultFontEmbedding = defaultFontEmbedding;
        DefaultFontColor = defaultFontColor == null
            ? DEFAULT_FONT_COLOR
            : defaultFontColor;
        DefaultFontSize = defaultFontSize.HasValue
            ? defaultFontSize.Value
            : DEFAULT_FONT_SIZE;
        DefaultFontStyle = defaultFontStyle.HasValue
            ? defaultFontStyle.Value
            : DEFAULT_FONT_STYLE;

        //set default replacement options
        ReplaceFontWithDefault = false;
        ReplaceEncodingWithDefault = true;
        ReplaceEmbeddingWithDefault = false;

        if (automaticalySetReplacementForNullables)
        {
            ReplaceSizeWithDefault = defaultFontSize.HasValue;
            ReplaceStyleWithDefault = defaultFontStyle.HasValue;
            ReplaceColorWithDefault = defaultFontColor != null;
        }

        //define default font
        DefaultBaseFont = BaseFont.CreateFont(DefaultFontPath, DefaultFontEncoding, DefaultFontEmbedding);

        //register system fonts
        FontFactory.RegisterDirectories();
    }

    protected Font GetBaseFont(Single size, Int32 style, BaseColor color)
    {
        var baseFont = new Font(DefaultBaseFont, size, style, color);

        return baseFont;
    }

    public override Font GetFont(String fontname, String encoding, Boolean embedded, Single size, Int32 style, BaseColor color, Boolean cached)
    {
        //eventually replace expected font properties
        size = ReplaceSizeWithDefault
            ? DefaultFontSize
            : size;
        style = ReplaceStyleWithDefault
            ? DefaultFontStyle
            : style;
        encoding = ReplaceEncodingWithDefault
            ? DefaultFontEncoding
            : encoding;
        embedded = ReplaceEmbeddingWithDefault
            ? DefaultFontEmbedding
            : embedded;

        //get font
        Font font = null;
        if (ReplaceFontWithDefault)
        {
            font = GetBaseFont(
                size,
                style,
                color);
        }
        else
        {
            font = FontFactory.GetFont(
                fontname,
                encoding,
                embedded,
                size,
                style,
                color,
                cached);

            if (font.BaseFont == null)
                font = GetBaseFont(
                    size,
                    style,
                    color);
        }

        return font;
    }
}
* * Контроллер тысяча сорок-девять
private const String DEFAULT_FONT_LOCATION = "~/Content/Fonts";
private const String DEFAULT_FONT_NAME = "arialn.ttf";

public FileStreamResult GetPdf()
{
    const string CONTENT_TYPE = "application/pdf"
    var fileName = "mySimple.pdf";
    var html = GetViewPageHtmlCode();
    //the way how to capture view HTML are described in other threads, e.g. 
    var css = Server.MapPath("~/Content/Pdf.css");
    using (var capturedActionStream = new MemoryStream(USED_ENCODING.GetBytes(html)))
    {
        using (var cssFile = new FileStream(css),  FileMode.Open))
        {
            var memoryStream = new MemoryStream();
            var document = new Document(PageSize.A4, 30, 30, 10, 10);
            //to create landscape, use PageSize.A4.Rotate() for pageSize
            var writer = PdfWriter.GetInstance(document, memoryStream);
            var worker = XMLWorkerHelper.GetInstance();
            var defaultFontPath = Server
                .MapPath(Path
                    .Combine(
                        DEFAULT_FONT_LOCATION,
                        DEFAULT_FONT_NAME));
            var fontProvider = new CustomFontFactory(defaultFontPath);

            document.Open();
            worker.ParseXHtml(writer, document, capturedActionStream, cssFile, fontProvider);
            writer.CloseStream = false;
            document.Close();
            memoryStream.Position = 0;

            //to enforce file download
            HttpContext.Response.AddHeader(
                "Content-Disposition",
                String.Format("attachment; filename={0}", fileName));
            var wrappedPdf = new FileStreamResult(memoryStream, CONTENT_TYPE);
            return wrappedPdf;
        }
    }
}

CSS:

body {
    background-color: white;
    font-size: .85em;
    font-family: "Trebuchet MS", Verdana, Helvetica, Sans-Serif;
    margin: 0;
    padding: 0;
    color: black;
}

p, ul {
    margin-bottom: 20px;
    line-height: 1.6em;
}

h1, h2, h3, h4, h5, h6 {
    font-size: 1.5em;
    color: #000;
}

Просмотр макета

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
        <title>@ViewBag.Title</title>
        <link href="@Url.Content("~/Content/Pdf.css")" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <div class="page">
            <div id="main">
                @RenderBody()
            </div>
        </div>
    </body>
    </html>

Просмотр страницы

@{
    ViewBag.Title = "PDF page title"
}

<h1>@ViewBag.Title</h1>

<p>
    ěščřžýáíéů ĚŠČŘŽÝÁÍÉŮ
</p>

Другие полезные (ре) источники:

2 голосов
/ 05 февраля 2011

При создании BaseFont необходимо указать, что вы хотите использовать символы UniCode. Этот ответ показывает, как.

1 голос
/ 05 февраля 2011

1) Сегодня был выпущен iText 5.0.6 с капитальным пересмотром кода преобразования HTML-> PDF. Я предлагаю вам попробовать новый код.

2) Я почти уверен, что установка DirectContent таким образом не повлияет на PDF-контент, сгенерированный HTMLWorker. Я на 99% уверен, что он [заново] установит шрифт, прежде чем начертит какой-либо текст.

3) Попробуйте обернуть строку в теги <font face="AFontThatActuallyContainsThoseCharacters">. Я серьезно сомневаюсь, что шрифт по умолчанию, выбранный HTMLWorker, подойдет для этой работы.

Неа. По умолчанию используется Helvetica с WinAnsiEncoding. Определенно не подходит ни к чему, кроме типичного английского / немецкого / французского / испанского.

Вы должны быть в состоянии использовать HTMLWorker.setStyleSheet, чтобы установить более дружественные настройки по умолчанию. Вы захотите установить для «лица» и «кодировки» что-то более дружественное к польскому. Я рекомендую «Identity-H» для кодировки, которая дает доступ ко всем символам шрифта, с которым вы идете, независимо от языка. Для шрифта в Windows имеется программа с именем charmap.exe, начиная с WayBack, которая покажет вам, какие символы есть у шрифта в данной кодировке (включая юникод). Семья «Ариал» выглядит хорошо, как и некоторые другие.


"новый код", вероятно, не изменит любое поведение, которое вы видите. Это рефакторинг, чтобы облегчить будущие (в следующем выпуске, насколько я понимаю) изменения.

Я предлагаю пойти с setStyleSheet():

   // step 3: we create a worker parse the document
   HTMLWorker worker = new HTMLWorker(document);

   StyleSheet sheet = new StyleSheet;

   HashMap<String, String> styleMap = new HashMap<String, String>();
   styleMap.put("face", "Arial"); // default font
   styleMap.put("encoding", "Identity-H"); // default encoding

   String tags[] = {"p", "div", ...};
   for (String tag : tags) {
     sheet.applyStyle( tag, styleMap );
   }

Я не уверен, но вы могли бы просто applyStyle("body", styleMap) и каскадировать все, что в нем содержится, но я не уверен. Я также не уверен, что это будет связано с вашим 1-строчным тестом, поскольку в нем нет тегов. IIRC, мы создаем тег body, если его нет, но я совсем не уверен.

...