freetype
[Top][All Lists]
Advanced

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

Re: [ft] CFF outline rendering problem


From: Róbert Márki
Subject: Re: [ft] CFF outline rendering problem
Date: Fri, 1 Oct 2010 08:46:25 +0200

I'm terribly sorry! I just thought you have used it before.
Basically, you only need to install Qt libraries to compile the example. Then you just have to execute "qmake" and then "make" commands from the terminal.

On Fri, Oct 1, 2010 at 8:34 AM, Werner LEMBERG <address@hidden> wrote:

> 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

#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]