blob: 895e32750e0dcae61815c8d181334e6d1327e60f [file] [log] [blame]
Robert Bieber6d615662010-06-23 20:18:31 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "rbfont.h"
Robert Bieber6f067932010-07-07 08:41:36 +000023#include "rbfontcache.h"
Robert Bieber6d609e02010-07-07 09:33:47 +000024#include "rbtextcache.h"
Robert Bieber6d615662010-06-23 20:18:31 +000025
Robert Bieber273b9d62010-06-25 05:14:13 +000026#include <QFont>
27#include <QBrush>
Robert Bieber6a044792010-07-05 22:15:17 +000028#include <QFile>
Robert Bieber39e25202010-07-06 19:19:11 +000029#include <QPainter>
30#include <QBitmap>
31#include <QImage>
Robert Biebereccc2bd2010-07-06 20:23:27 +000032#include <QSettings>
Robert Bieber273b9d62010-06-25 05:14:13 +000033
Robert Bieber6f067932010-07-07 08:41:36 +000034#include <QDebug>
35
Robert Bieber39e25202010-07-06 19:19:11 +000036quint16 RBFont::maxFontSizeFor16BitOffsets = 0xFFDB;
Robert Bieber6a044792010-07-05 22:15:17 +000037
38RBFont::RBFont(QString file)
Robert Bieber39e25202010-07-06 19:19:11 +000039 : valid(false), imageData(0), offsetData(0), widthData(0)
Robert Bieber6d615662010-06-23 20:18:31 +000040{
Robert Bieber6a044792010-07-05 22:15:17 +000041
Robert Bieberdfc109a2010-08-13 19:14:54 +000042 bool badFile = false;
43
Robert Bieber6a044792010-07-05 22:15:17 +000044 /* Attempting to locate the correct file name */
45 if(!QFile::exists(file))
Robert Biebereccc2bd2010-07-06 20:23:27 +000046 {
47 /* Checking in the fonts repository */
48 QSettings settings;
49 settings.beginGroup("RBFont");
50
51 file = file.split("/").last();
52 file = settings.value("fontDir", "").toString() + "/" + file;
53
54 settings.endGroup();
55
56 if(!QFile::exists(file))
Robert Bieberdfc109a2010-08-13 19:14:54 +000057 {
Robert Biebereccc2bd2010-07-06 20:23:27 +000058 file = ":/fonts/08-Schumacher-Clean.fnt";
Robert Bieberdfc109a2010-08-13 19:14:54 +000059
60 badFile = true;
61 }
Robert Biebereccc2bd2010-07-06 20:23:27 +000062 }
Robert Bieber6a044792010-07-05 22:15:17 +000063 header.insert("filename", file);
64
Robert Bieber6f067932010-07-07 08:41:36 +000065 /* Checking for a cache entry */
66 RBFontCache::CacheInfo* cache = RBFontCache::lookup(file);
67 if(cache)
68 {
69 imageData = cache->imageData;
70 offsetData = cache->offsetData;
71 widthData = cache->widthData;
72 header = cache->header;
73
Robert Bieberdfc109a2010-08-13 19:14:54 +000074 if(!badFile)
75 valid = true;
76
Robert Bieber6f067932010-07-07 08:41:36 +000077 return;
78 }
79
Robert Bieber6a044792010-07-05 22:15:17 +000080 /* Opening the file */
81 QFile fin(file);
82 fin.open(QFile::ReadOnly);
83
84 /* Loading the header info */
Robert Bieber39e25202010-07-06 19:19:11 +000085 quint8 byte;
Robert Bieber6a044792010-07-05 22:15:17 +000086 quint16 word;
87 quint32 dword;
88
89 QDataStream data(&fin);
90 data.setByteOrder(QDataStream::LittleEndian);
91
92 /* Grabbing the magic number and version */
93 data >> dword;
94 header.insert("version", dword);
95
96 /* Max font width */
97 data >> word;
98 header.insert("maxwidth", word);
99
100 /* Font height */
101 data >> word;
102 header.insert("height", word);
103
104 /* Ascent */
105 data >> word;
106 header.insert("ascent", word);
107
108 /* Padding */
109 data >> word;
110
111 /* First character code */
112 data >> dword;
113 header.insert("firstchar", dword);
114
115 /* Default character code */
116 data >> dword;
117 header.insert("defaultchar", dword);
118
119 /* Number of characters */
120 data >> dword;
121 header.insert("size", dword);
122
123 /* Bytes of imagebits in file */
124 data >> dword;
125 header.insert("nbits", dword);
126
127 /* Longs (dword) of offset data in file */
128 data >> dword;
129 header.insert("noffset", dword);
130
131 /* Bytes of width data in file */
132 data >> dword;
133 header.insert("nwidth", dword);
134
Robert Bieber39e25202010-07-06 19:19:11 +0000135 /* Loading the image data */
136 imageData = new quint8[header.value("nbits").toInt()];
Robert Biebere03d3732010-07-07 07:38:38 +0000137 data.readRawData(reinterpret_cast<char*>(imageData),
138 header.value("nbits").toInt());
Robert Bieber6a044792010-07-05 22:15:17 +0000139
Robert Bieber39e25202010-07-06 19:19:11 +0000140 /* Aligning on 16-bit boundary */
141 if(header.value("nbits").toInt() % 2 == 1)
142 data >> byte;
143
144 /* Loading the offset table if necessary */
145 if(header.value("noffset").toInt() > 0)
146 {
Robert Bieberf65ed0d2010-07-11 05:12:11 +0000147 int bytesToRead;
148 if(header.value("nbits").toInt() > maxFontSizeFor16BitOffsets)
149 bytesToRead = 4 * header.value("noffset").toInt();
150 else
151 bytesToRead = 2 * header.value("noffset").toInt();
152 offsetData = new quint16[bytesToRead];
153 data.readRawData(reinterpret_cast<char*>(offsetData), bytesToRead);
Robert Bieber39e25202010-07-06 19:19:11 +0000154 }
155
156 /* Loading the width table if necessary */
157 if(header.value("nwidth").toInt() > 0)
158 {
159 widthData = new quint8[header.value("nwidth").toInt()];
Robert Biebere03d3732010-07-07 07:38:38 +0000160 data.readRawData(reinterpret_cast<char*>(widthData),
161 header.value("nwidth").toInt());
Robert Bieber39e25202010-07-06 19:19:11 +0000162 }
163
164 fin.close();
165
Robert Bieber6f067932010-07-07 08:41:36 +0000166 /* Caching the font data */
167 cache = new RBFontCache::CacheInfo;
168 cache->imageData = imageData;
169 cache->offsetData = offsetData;
170 cache->widthData = widthData;
171 cache->header = header;
172 RBFontCache::insert(file, cache);
173
Robert Bieberdfc109a2010-08-13 19:14:54 +0000174 if(!badFile)
175 valid = true;
176
Robert Bieber6d615662010-06-23 20:18:31 +0000177}
178
179RBFont::~RBFont()
180{
181}
Robert Bieber273b9d62010-06-25 05:14:13 +0000182
Robert Bieber3214e372010-07-07 06:50:30 +0000183RBText* RBFont::renderText(QString text, QColor color, int viewWidth,
184 QGraphicsItem *parent)
Robert Bieber273b9d62010-06-25 05:14:13 +0000185{
Robert Bieber6d609e02010-07-07 09:33:47 +0000186
187 /* Checking for a cache hit first */
188 QImage* image = RBTextCache::lookup(header.value("filename").toString()
189 + text);
190 if(image)
191 return new RBText(image, viewWidth, parent);
192
Robert Bieber39e25202010-07-06 19:19:11 +0000193 int firstChar = header.value("firstchar").toInt();
194 int height = header.value("height").toInt();
195 int maxWidth = header.value("maxwidth").toInt();
196
Robert Bieberf65ed0d2010-07-11 05:12:11 +0000197 bool extendedSet = header.value("nbits").
198 toUInt() > maxFontSizeFor16BitOffsets;
199
Robert Bieber39e25202010-07-06 19:19:11 +0000200 /* First we determine the width of the combined text */
201 QList<int> widths;
202 for(int i = 0; i < text.length(); i++)
203 {
204 if(widthData)
205 widths.append(widthData[text[i].unicode() - firstChar]);
206 else
207 widths.append(maxWidth);
208 }
209
210 int totalWidth = 0;
211 for(int i = 0; i < widths.count(); i++)
212 totalWidth += widths[i];
213
Robert Bieber6d609e02010-07-07 09:33:47 +0000214 image = new QImage(totalWidth, height, QImage::Format_Indexed8);
Robert Bieber39e25202010-07-06 19:19:11 +0000215
Robert Bieber6d609e02010-07-07 09:33:47 +0000216 image->setColor(0, qRgba(0,0,0,0));
217 image->setColor(1, color.rgb());
Robert Bieber39e25202010-07-06 19:19:11 +0000218
219 /* Drawing the text */
220 int startX = 0;
221 for(int i = 0; i < text.length(); i++)
222 {
223 unsigned int offset;
224 if(offsetData)
Robert Bieberf65ed0d2010-07-11 05:12:11 +0000225 {
226 if(extendedSet)
227 offset = reinterpret_cast<quint32*>(offsetData)[text[i].unicode() - firstChar];
228 else
229 offset = offsetData[text[i].unicode() - firstChar];
230 }
Robert Bieber39e25202010-07-06 19:19:11 +0000231 else
Robert Bieberf65ed0d2010-07-11 05:12:11 +0000232 {
Robert Bieber39e25202010-07-06 19:19:11 +0000233 offset = (text[i].unicode() - firstChar) * maxWidth;
Robert Bieberf65ed0d2010-07-11 05:12:11 +0000234 }
Robert Bieber39e25202010-07-06 19:19:11 +0000235
236 int bytesHigh = height / 8;
237 if(height % 8 > 0)
238 bytesHigh++;
239
240 int bytes = bytesHigh * widths[i];
241
242 for(int byte = 0; byte < bytes; byte++)
243 {
244 int x = startX + byte % widths[i];
245 int y = byte / widths[i] * 8;
246 quint8 data = imageData[offset];
247 quint8 mask = 0x1;
248 for(int bit = 0; bit < 8; bit++)
249 {
250 if(mask & data)
Robert Bieber6d609e02010-07-07 09:33:47 +0000251 image->setPixel(x, y, 1);
Robert Bieber39e25202010-07-06 19:19:11 +0000252 else
Robert Bieber6d609e02010-07-07 09:33:47 +0000253 image->setPixel(x, y, 0);
Robert Bieber39e25202010-07-06 19:19:11 +0000254
255 y++;
256 mask <<= 1;
257 if(y >= height)
258 break;
259 }
260
261 offset++;
262 }
263
264 startX += widths[i];
265 }
266
Robert Bieber6d609e02010-07-07 09:33:47 +0000267 RBTextCache::insert(header.value("filename").toString() + text, image);
Robert Bieber3214e372010-07-07 06:50:30 +0000268 return new RBText(image, viewWidth, parent);
Robert Bieber39e25202010-07-06 19:19:11 +0000269
Robert Bieber273b9d62010-06-25 05:14:13 +0000270}