freetype
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [ft] CFF outline rendering problem


From: Werner LEMBERG
Subject: Re: [ft] CFF outline rendering problem
Date: Fri, 01 Oct 2010 08:34:56 +0200 (CEST)

> I think I've found a bug in the cff renderer algorithm or I'm doing
> something seriously wrong.  When rendering glyphs with cff outlines
> (otf, pfb fonts) the control points which are located under the
> baseline are connected with straight lines, for ttf fonts all the
> glyphs are rendered correctly.  This problem occurs only when I use
> direct rendering with the FT_RASTER_FLAG_DIRECT flag, if I render
> the glyph to a bitmap with FT the problem doesn't occur.  This
> problem is present in every version of FT that I've tested (2.1,
> 2.2, 2.3, 2.4).
> 
> [...] this
> <http://www.filefactory.com/file/b36458b/n/renderer_problem.zip> is
> the example app, and this
> <http://www.filefactory.com/file/b36458c/n/letter_g.png> is how FT
> renders glyphs.

I've now downloaded your files, but please tell me how to compile it,
since I've never done Qt development...

Maybe others find the problem more quickly than me; I've thus attached
the image and the source code files.


    Werner

PNG image

#include <QtGui/QApplication>
#include <QWidget>
#include <QPainter>
#include <QFile>
#include <QImage>
#include <iostream>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_TYPES_H
#include FT_OUTLINE_H
#include FT_RENDER_H

QString g_usageText = "usage:\n"
                      "renderer_problem FONT_PATH CHARACTER SIZE "
                      "DIRECT_RENDERING_MODE(1|0)";
#define TRUNC(x)    ((x) >> 6)

class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(const QString& fileName, QChar character, int pointSize
           ,bool directRender
           ,QWidget *parent = 0)
               :QWidget(parent), m_directRender(directRender)
    {
        FT_Error error = 0;
        m_face = 0;
        m_library = 0;
        error = FT_Init_FreeType(&m_library);
        if(!error)
        {
            error = FT_New_Face(m_library, fileName.toAscii().constData(), 0,
                                &m_face);
            if(!error)
            {
                error = FT_Set_Char_Size(m_face,
                                         0,
                                         pointSize * 64,
                                         physicalDpiX(),
                                         physicalDpiY());
                FT_UInt glyph_index = 0;
                glyph_index = FT_Get_Char_Index(m_face, character.unicode());
                error = FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT);

                FT_Pos left = m_face->glyph->metrics.horiBearingX;
                FT_Pos right = m_face->glyph->metrics.horiBearingX
                               + m_face->glyph->metrics.width;
                FT_Pos top = m_face->glyph->metrics.horiBearingY;
                FT_Pos bottom = m_face->glyph->metrics.horiBearingY
                                - m_face->glyph->metrics.height;
                m_glyphRect = QRect(QPoint(TRUNC(left),
                                           -TRUNC(top) + 1),
                                    QSize(TRUNC(right-left) + 1,
                                          TRUNC(top-bottom) + 1));
                setFixedSize(m_glyphRect.width(), m_glyphRect.height());
            }
        }
    }
    ~Widget()
    {
        FT_Done_Face(m_face);
        FT_Done_Library(m_library);
    }
private:
    FT_Library m_library;
    FT_Face m_face;
    QRect m_glyphRect;
    bool m_directRender;
    static void graySpans(int y, int count, const FT_Span_ *spans, void *user)
    {
        QPainter *painter = (QPainter *)user;
        y = -y;
        for(int i = 0; i < count; i++)
        {
            const FT_Span span = spans[i];
            qreal opacity = (qreal(span.coverage) / 255.0);
            painter->setOpacity(opacity);
            if(span.len > 0)
            {
                painter->drawLine(span.x, y, span.x + span.len, y);
            }
        }
    }
protected:
    void paintEvent(QPaintEvent *event)
    {
        QWidget::paintEvent(event);
        if(m_library && m_face)
        {
            FT_Error error = 0;
            QPainter painter(this);
            painter.translate(-m_glyphRect.x(), -m_glyphRect.y());
            if(m_directRender)
            {
                FT_Raster_Params params;
                params.target = 0;
                params.flags = FT_RASTER_FLAG_DIRECT | FT_RASTER_FLAG_AA;
                params.user = &painter;
                params.gray_spans = &Widget::graySpans;
                params.black_spans = 0;
                params.bit_set = 0;
                params.bit_test = 0;
                FT_Outline* outline = &m_face->glyph->outline;
                FT_Outline_Render(m_library, outline, &params);
            }
            else
            {
                error = FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL);
                QImage glyphImage(m_face->glyph->bitmap.buffer
                                  ,m_face->glyph->bitmap.width
                                  ,m_face->glyph->bitmap.rows
                                  ,m_face->glyph->bitmap.pitch
                                  ,QImage::Format_Indexed8);
                painter.translate(m_glyphRect.x(), m_glyphRect.y());
                QVector<QRgb> colorTable;
                for(int i = 0; i < 256; ++i)
                    colorTable << qRgba(0, 0, 0, i);
                glyphImage.setColorTable(colorTable);
                painter.drawImage(QPoint(0, 0), glyphImage);
            }
        }
    }
};

int main(int argc, char **argv)
{
    bool status = false;
    if(argc == 5)
    {
        bool isSizeOk = false;
        QString path = argv[1];
        QChar character = *argv[2];
        int size = QString(argv[3]).toInt(&isSizeOk);
        bool directRender = QString(argv[4]).toInt();
        if(QFile::exists(path) && isSizeOk)
        {
            status = true;
            QApplication a(argc, argv);
            Widget w(path, character, size, directRender);
            w.show();
            return a.exec();
        }
    }
    if(!status)
    {
        std::cout << qPrintable(g_usageText) << std::endl;
        return 0;
    }
}
#include "main.moc"
QT       += core gui
TARGET = renderer_problem
TEMPLATE = app
SOURCES += main.cpp
MOC_DIR = ./moc
LIBS +=  -lz -lfreetype
INCLUDEPATH += $$MOC_DIR \
    /usr/local/include \
    /usr/local/include/freetype2


reply via email to

[Prev in Thread] Current Thread [Next in Thread]