Robert Bieber | 6d61566 | 2010-06-23 20:18:31 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 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 Bieber | 6f06793 | 2010-07-07 08:41:36 +0000 | [diff] [blame] | 23 | #include "rbfontcache.h" |
Robert Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 24 | #include "rbtextcache.h" |
Robert Bieber | 6d61566 | 2010-06-23 20:18:31 +0000 | [diff] [blame] | 25 | |
Robert Bieber | 273b9d6 | 2010-06-25 05:14:13 +0000 | [diff] [blame] | 26 | #include <QFont> |
| 27 | #include <QBrush> |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 28 | #include <QFile> |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 29 | #include <QPainter> |
| 30 | #include <QBitmap> |
| 31 | #include <QImage> |
Robert Bieber | eccc2bd | 2010-07-06 20:23:27 +0000 | [diff] [blame] | 32 | #include <QSettings> |
Robert Bieber | 273b9d6 | 2010-06-25 05:14:13 +0000 | [diff] [blame] | 33 | |
Robert Bieber | 6f06793 | 2010-07-07 08:41:36 +0000 | [diff] [blame] | 34 | #include <QDebug> |
| 35 | |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 36 | quint16 RBFont::maxFontSizeFor16BitOffsets = 0xFFDB; |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 37 | |
| 38 | RBFont::RBFont(QString file) |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 39 | : valid(false), imageData(0), offsetData(0), widthData(0) |
Robert Bieber | 6d61566 | 2010-06-23 20:18:31 +0000 | [diff] [blame] | 40 | { |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 41 | |
Robert Bieber | dfc109a | 2010-08-13 19:14:54 +0000 | [diff] [blame] | 42 | bool badFile = false; |
| 43 | |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 44 | /* Attempting to locate the correct file name */ |
| 45 | if(!QFile::exists(file)) |
Robert Bieber | eccc2bd | 2010-07-06 20:23:27 +0000 | [diff] [blame] | 46 | { |
| 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 Bieber | dfc109a | 2010-08-13 19:14:54 +0000 | [diff] [blame] | 57 | { |
Robert Bieber | eccc2bd | 2010-07-06 20:23:27 +0000 | [diff] [blame] | 58 | file = ":/fonts/08-Schumacher-Clean.fnt"; |
Robert Bieber | dfc109a | 2010-08-13 19:14:54 +0000 | [diff] [blame] | 59 | |
| 60 | badFile = true; |
| 61 | } |
Robert Bieber | eccc2bd | 2010-07-06 20:23:27 +0000 | [diff] [blame] | 62 | } |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 63 | header.insert("filename", file); |
| 64 | |
Robert Bieber | 6f06793 | 2010-07-07 08:41:36 +0000 | [diff] [blame] | 65 | /* 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 Bieber | dfc109a | 2010-08-13 19:14:54 +0000 | [diff] [blame] | 74 | if(!badFile) |
| 75 | valid = true; |
| 76 | |
Robert Bieber | 6f06793 | 2010-07-07 08:41:36 +0000 | [diff] [blame] | 77 | return; |
| 78 | } |
| 79 | |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 80 | /* Opening the file */ |
| 81 | QFile fin(file); |
| 82 | fin.open(QFile::ReadOnly); |
| 83 | |
| 84 | /* Loading the header info */ |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 85 | quint8 byte; |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 86 | 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 Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 135 | /* Loading the image data */ |
| 136 | imageData = new quint8[header.value("nbits").toInt()]; |
Robert Bieber | e03d373 | 2010-07-07 07:38:38 +0000 | [diff] [blame] | 137 | data.readRawData(reinterpret_cast<char*>(imageData), |
| 138 | header.value("nbits").toInt()); |
Robert Bieber | 6a04479 | 2010-07-05 22:15:17 +0000 | [diff] [blame] | 139 | |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 140 | /* 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 Bieber | f65ed0d | 2010-07-11 05:12:11 +0000 | [diff] [blame] | 147 | 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 Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 154 | } |
| 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 Bieber | e03d373 | 2010-07-07 07:38:38 +0000 | [diff] [blame] | 160 | data.readRawData(reinterpret_cast<char*>(widthData), |
| 161 | header.value("nwidth").toInt()); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | fin.close(); |
| 165 | |
Robert Bieber | 6f06793 | 2010-07-07 08:41:36 +0000 | [diff] [blame] | 166 | /* 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 Bieber | dfc109a | 2010-08-13 19:14:54 +0000 | [diff] [blame] | 174 | if(!badFile) |
| 175 | valid = true; |
| 176 | |
Robert Bieber | 6d61566 | 2010-06-23 20:18:31 +0000 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | RBFont::~RBFont() |
| 180 | { |
| 181 | } |
Robert Bieber | 273b9d6 | 2010-06-25 05:14:13 +0000 | [diff] [blame] | 182 | |
Robert Bieber | 3214e37 | 2010-07-07 06:50:30 +0000 | [diff] [blame] | 183 | RBText* RBFont::renderText(QString text, QColor color, int viewWidth, |
| 184 | QGraphicsItem *parent) |
Robert Bieber | 273b9d6 | 2010-06-25 05:14:13 +0000 | [diff] [blame] | 185 | { |
Robert Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 186 | |
| 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 Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 193 | int firstChar = header.value("firstchar").toInt(); |
| 194 | int height = header.value("height").toInt(); |
| 195 | int maxWidth = header.value("maxwidth").toInt(); |
| 196 | |
Robert Bieber | f65ed0d | 2010-07-11 05:12:11 +0000 | [diff] [blame] | 197 | bool extendedSet = header.value("nbits"). |
| 198 | toUInt() > maxFontSizeFor16BitOffsets; |
| 199 | |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 200 | /* 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 Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 214 | image = new QImage(totalWidth, height, QImage::Format_Indexed8); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 215 | |
Robert Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 216 | image->setColor(0, qRgba(0,0,0,0)); |
| 217 | image->setColor(1, color.rgb()); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 218 | |
| 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 Bieber | f65ed0d | 2010-07-11 05:12:11 +0000 | [diff] [blame] | 225 | { |
| 226 | if(extendedSet) |
| 227 | offset = reinterpret_cast<quint32*>(offsetData)[text[i].unicode() - firstChar]; |
| 228 | else |
| 229 | offset = offsetData[text[i].unicode() - firstChar]; |
| 230 | } |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 231 | else |
Robert Bieber | f65ed0d | 2010-07-11 05:12:11 +0000 | [diff] [blame] | 232 | { |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 233 | offset = (text[i].unicode() - firstChar) * maxWidth; |
Robert Bieber | f65ed0d | 2010-07-11 05:12:11 +0000 | [diff] [blame] | 234 | } |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 235 | |
| 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 Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 251 | image->setPixel(x, y, 1); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 252 | else |
Robert Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 253 | image->setPixel(x, y, 0); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 254 | |
| 255 | y++; |
| 256 | mask <<= 1; |
| 257 | if(y >= height) |
| 258 | break; |
| 259 | } |
| 260 | |
| 261 | offset++; |
| 262 | } |
| 263 | |
| 264 | startX += widths[i]; |
| 265 | } |
| 266 | |
Robert Bieber | 6d609e0 | 2010-07-07 09:33:47 +0000 | [diff] [blame] | 267 | RBTextCache::insert(header.value("filename").toString() + text, image); |
Robert Bieber | 3214e37 | 2010-07-07 06:50:30 +0000 | [diff] [blame] | 268 | return new RBText(image, viewWidth, parent); |
Robert Bieber | 39e2520 | 2010-07-06 19:19:11 +0000 | [diff] [blame] | 269 | |
Robert Bieber | 273b9d6 | 2010-06-25 05:14:13 +0000 | [diff] [blame] | 270 | } |