3c944b3d4cc01e8c6365746dbc88afe7e0462487
[profile/ivi/qtdeclarative.git] / tools / distfieldgen / main.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt scene graph research project.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore>
43 #include <QtGui>
44
45 #include <private/qsgdistancefieldglyphcache_p.h>
46
47 static void usage()
48 {
49     qWarning("Usage: distfieldgen [options] <font_filename>");
50     qWarning(" ");
51     qWarning("Distfieldgen generates distance-field renderings of the provided font file,");
52     qWarning("one for each font family/style it contains.");
53     qWarning("Unless the QT_QML_DISTFIELDDIR environment variable is set, the renderings are");
54     qWarning("saved in the fonts/distancefields directory where the Qt libraries are located.");
55     qWarning("You can also override the output directory with the -d option.");
56     qWarning(" ");
57     qWarning(" options:");
58     qWarning("  -d <directory>................................ output directory");
59     qWarning("  --no-multithread.............................. don't use multiple threads to render distance-fields");
60     qWarning("  --force-all-styles............................ force rendering of styles Normal, Bold, Italic and Bold Italic");
61     qWarning("  -styles \"style1,style2,..\".................... force rendering of specified styles");
62
63     qWarning(" ");
64     exit(1);
65 }
66
67 void printProgress(int p)
68 {
69     printf("\r  [");
70     for (int i = 0; i < 50; ++i)
71         printf(i < p / 2 ? "=" : " ");
72     printf("]");
73     printf(" %d%%", p);
74     fflush(stdout);
75 }
76
77 class DistFieldGenTask : public QRunnable
78 {
79 public:
80     DistFieldGenTask(QSGDistanceFieldGlyphCache *atlas, int c, int nbGlyph, QMap<int, QImage> *outList)
81         : QRunnable()
82         , m_atlas(atlas)
83         , m_char(c)
84         , m_nbGlyph(nbGlyph)
85         , m_outList(outList)
86     { }
87
88     void run()
89     {
90         QImage df = m_atlas->renderDistanceFieldGlyph(m_char);
91         QMutexLocker lock(&m_mutex);
92         m_outList->insert(m_char, df);
93         printProgress(float(m_outList->count()) / m_nbGlyph * 100);
94     }
95
96     static QMutex m_mutex;
97     QSGDistanceFieldGlyphCache *m_atlas;
98     int m_char;
99     int m_nbGlyph;
100     QMap<int, QImage> *m_outList;
101 };
102
103 QMutex DistFieldGenTask::m_mutex;
104
105 static void generateDistanceFieldForFont(const QFont &font, const QString &destinationDir, bool multithread)
106 {
107     QSGDistanceFieldGlyphCache *atlas = QSGDistanceFieldGlyphCache::get(QGLContext::currentContext(), font);
108     QFontDatabase db;
109     QString fontString = font.family() + QLatin1String(" ") + db.styleString(font);
110     qWarning("> Generating distance-field for font '%s' (%d glyphs)", fontString.toLatin1().constData(), atlas->glyphCount());
111
112     QMap<int, QImage> distfields;
113     for (int i = 0; i < atlas->glyphCount(); ++i) {
114         if (multithread) {
115             DistFieldGenTask *task = new DistFieldGenTask(atlas, i, atlas->glyphCount(), &distfields);
116             QThreadPool::globalInstance()->start(task);
117         } else {
118             QImage df = atlas->renderDistanceFieldGlyph(i);
119             distfields.insert(i, df);
120             printProgress(float(distfields.count()) / atlas->glyphCount() * 100);
121         }
122     }
123
124     if (multithread)
125         QThreadPool::globalInstance()->waitForDone();
126
127     // Combine dist fields in one image
128     int size = qCeil(qSqrt(qreal(atlas->glyphCount()))) * 64;
129     QImage output(size, size, QImage::Format_ARGB32_Premultiplied);
130     output.fill(Qt::transparent);
131     QPainter p(&output);
132     int x, y = 0;
133     for (QMap<int, QImage>::const_iterator i = distfields.constBegin(); i != distfields.constEnd(); ++i) {
134         p.drawImage(x, y, i.value());
135         x += 64;
136         if (x >= size) {
137             x = 0;
138             y += 64;
139         }
140     }
141     p.end();
142     printProgress(100);
143     printf("\n");
144
145     // Save output
146     QFileInfo dfi(destinationDir);
147     if (!dfi.isDir()) {
148         qWarning("Error: '%s' is not a directory.", destinationDir.toLatin1().constData());
149         qWarning(" ");
150         exit(1);
151     }
152
153     QString filename = font.family();
154     filename.remove(QLatin1String(" "));
155     QString italic = font.italic() ? QLatin1String("i") : QLatin1String("");
156     QString bold = font.weight() > QFont::Normal ? QLatin1String("b") : QLatin1String("");
157     filename = filename + bold + italic;
158     QString out = QString(QLatin1String("%1/%2.png")).arg(destinationDir).arg(filename);
159     output.save(out);
160     qWarning("  Distance-field saved to '%s'\n", out.toLatin1().constData());
161 }
162
163 class MyWidget : public QGLWidget
164 {
165     Q_OBJECT
166 public:
167     MyWidget()
168         : QGLWidget()
169     { }
170
171     ~MyWidget() { }
172
173     void showEvent(QShowEvent *e)
174     {
175         QStringList args = QApplication::arguments();
176
177         bool noMultithread = args.contains(QLatin1String("--no-multithread"));
178         bool forceAllStyles = args.contains(QLatin1String("--force-all-styles"));
179
180         QString fontFile;
181         QString destDir;
182         for (int i = 0; i < args.count(); ++i) {
183             QString a = args.at(i);
184             if (!a.startsWith('-') && QFileInfo(a).exists())
185                 fontFile = a;
186             if (a == QLatin1String("-d"))
187                 destDir = args.at(++i);
188         }
189         if (destDir.isEmpty()) {
190             destDir = QFileInfo(fontFile).canonicalPath();
191         }
192
193         QStringList customStyles;
194         if (args.contains(QLatin1String("-styles"))) {
195             int index = args.indexOf(QLatin1String("-styles"));
196             QString styles = args.at(index + 1);
197             customStyles = styles.split(QLatin1String(","));
198         }
199
200         // Load the font
201         int fontID = QFontDatabase::addApplicationFont(fontFile);
202         if (fontID == -1) {
203             qWarning("Error: Invalid font file.");
204             qWarning(" ");
205             exit(1);
206         }
207
208         QStringList allStyles = QStringList() << QLatin1String("Normal")
209                                               << QLatin1String("Bold")
210                                               << QLatin1String("Italic")
211                                               << QLatin1String("Bold Italic");
212
213         // Generate distance-fields for all families and all styles provided by the font file
214         QFontDatabase fontDatabase;
215         QStringList families = QFontDatabase::applicationFontFamilies(fontID);
216         int famCount = families.count();
217         for (int i = 0; i < famCount; ++i) {
218             QStringList styles;
219             if (forceAllStyles)
220                 styles = allStyles;
221             else if (customStyles.count() > 0)
222                 styles = customStyles;
223             else
224                 styles = fontDatabase.styles(families.at(i));
225
226             int styleCount = styles.count();
227             for (int j = 0; j < styleCount; ++j) {
228                 QFont font;
229                 if (forceAllStyles || customStyles.count() > 0) {
230                     int weight = styles.at(j).contains(QLatin1String("Bold")) ? QFont::Bold : QFont::Normal;
231                     font = QFont(families.at(i), 10, weight, styles.at(j).contains(QLatin1String("Italic")));
232                 } else {
233                     font = fontDatabase.font(families.at(i), styles.at(j), 10); // point size is ignored
234                 }
235                 generateDistanceFieldForFont(font, destDir, !noMultithread);
236             }
237         }
238
239         exit(0);
240     }
241 };
242
243 int main(int argc, char *argv[])
244 {
245     QApplication app(argc, argv);
246     QStringList args = QApplication::arguments();
247
248     if (argc < 2
249             || args.contains(QLatin1String("--help"))
250             || args.contains(QLatin1String("-help"))
251             || args.contains(QLatin1String("--h"))
252             || args.contains(QLatin1String("-h")))
253         usage();
254
255
256    MyWidget w;
257    w.show();
258
259    return app.exec();
260 }
261
262 #include "main.moc"