Replaced all std::cout with kDebug.
[tagua/yd.git] / src / loader / image.cpp
blobb696f10c5ecae3ef90fc231297b5f149d6212d31
1 /*
2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 */
12 #include <QFont>
13 #include <QFontDatabase>
14 #include <QPainter>
15 #include <QPainterPath>
16 #include <QSvgRenderer>
17 #include <iostream>
18 #include "common.h"
19 #include "imageeffects.h"
20 #include "loader/context.h"
21 #include "loader/image.h"
23 namespace Loader {
25 //BEGIN Font-------------------------------------------------------------------
27 Font::Font(int id, int size)
28 : m_id(id)
29 , m_families(QFontDatabase::applicationFontFamilies(id))
30 , m_font(m_families.empty()?QString():m_families[0], size) {
31 //for(int i=0;i<m_families.size();i++)
32 //kDebug() << "Familiy[" << i << "] = " << m_families[i];
35 Font::Font(const QFont& font)
36 : m_id(-1)
37 , m_font(font) {
41 Font::~Font() {
42 if(m_id != -1)
43 QFontDatabase::removeApplicationFont(m_id);
46 FontPtr Font::create(Context* ctx, const QString& file) {
47 FontPtr retv;
48 if(FontPtr *f = ctx->get<FontPtr>(file))
49 retv = *f;
50 else {
51 int font_id = QFontDatabase::addApplicationFont(file);
52 if(font_id != -1) {
53 retv = FontPtr(new Font(font_id) );
55 ctx->put(file, retv);
57 return retv;
60 //END Font---------------------------------------------------------------------
63 //BEGIN FontGlyph--------------------------------------------------------------
65 class FontGlyph {
66 public:
67 int m_height;
68 QPainterPath m_path;
69 bool m_inner_background_init;
70 QImage m_inner_background;
72 FontGlyph() : m_inner_background_init(false) {}
75 //END FontGlyph----------------------------------------------------------------
77 typedef boost::shared_ptr<QSvgRenderer> Svg;
78 typedef boost::shared_ptr<FontGlyph> FontGlyphPtr;
81 //BEGIN Image------------------------------------------------------------------
83 Image::Image(int width,
84 int height)
85 : m_image(width, height, QImage::Format_ARGB32_Premultiplied )
86 , m_draw_opacity(1.0)
87 , m_draw_over(true) {
89 QPainter p(&m_image);
90 init_painter(&p);
92 p.fillRect(QRect(0,0,width,height), Qt::blue);
96 Image::Image(Context* ctx,
97 const QString& file,
98 bool use_cache)
99 : m_draw_opacity(1.0)
100 , m_draw_over(true) {
102 if( QImage *i = ctx->get<QImage>(file) )
103 m_image = *i;
104 else {
105 m_image = QImage(file);
106 if(use_cache) ctx->put(file, m_image);
111 void Image::init_painter(QPainter* p) {
112 p->setMatrix(m_draw_matrix);
113 p->setOpacity(m_draw_opacity);
114 p->setRenderHint(QPainter::Antialiasing);
115 p->setRenderHint(QPainter::TextAntialiasing);
116 p->setRenderHint(QPainter::SmoothPixmapTransform);
117 if(m_draw_over)
118 p->setCompositionMode(QPainter::CompositionMode_SourceOver);
119 else
120 p->setCompositionMode(QPainter::CompositionMode_Source);
124 void Image::clear(const QColor& color) {
125 QPainter p(&m_image);
126 p.setCompositionMode(QPainter::CompositionMode_Source);
127 p.fillRect(0,0,width(),height(), color);
131 void Image::fillRect(const QRectF& rect,
132 const QBrush& brush) {
133 QPainter p(&m_image);
134 init_painter(&p);
136 p.fillRect(rect, brush);
140 void Image::drawLine(const QPointF& from,
141 const QPointF& to,
142 const QColor& col,
143 double width) {
144 QPainter p(&m_image);
145 init_painter(&p);
147 p.setPen( QPen( col, width ) );
148 p.drawLine(from, to);
152 void Image::drawImage(const QRectF& dest,
153 const Image& src_img,
154 const QRectF& src) {
155 QPainter p(&m_image);
156 init_painter(&p);
158 p.drawImage(dest, src_img.m_image, src.isNull()
159 ? src_img.m_image.rect() : src);
163 bool Image::drawImage(Context* ctx,
164 const QRectF& dest,
165 const QString& src_img,
166 const QRectF& src,
167 bool use_cache) {
168 Image img(ctx, src_img, use_cache);
169 if(img.width()==0 || img.height()==0)
170 return false;
171 QRectF s = src.isNull() ? QRectF(0,0,img.width(),img.height()) :
172 QRectF(src.x()*img.width(),src.y()*img.height(),
173 src.width()*img.width(),src.height()*img.height());
175 QPainter p(&m_image);
176 init_painter(&p);
178 p.drawImage(dest, img.m_image, s);
179 return true;
183 bool Image::drawSVG(Context* ctx,
184 const QRectF& dest,
185 const QString& file) {
186 Svg svg;
188 if( Svg *s = ctx->get<Svg>(file) )
189 svg = *s;
190 else {
191 svg = Svg(new QSvgRenderer(file));
192 if(!svg->isValid())
193 svg = Svg();
194 ctx->put(file, svg);
197 if(!svg)
198 return false;
200 QPainter p(&m_image);
201 init_painter(&p);
203 p.setViewport(dest.toRect());
204 svg->render(&p);
205 return true;
209 bool Image::drawGlyph(Context* ctx,
210 const QRectF& dest,
211 const QString& file,
212 unsigned int glyph_num,
213 const QBrush& _fg,
214 const QBrush& _bg,
215 double border,
216 bool draw_inner_bg) {
217 QChar glyph(glyph_num);
218 FontGlyphPtr font_glyph;
220 QString k = file + qPrintf(":%04x", glyph_num);
221 if(FontGlyphPtr *f = ctx->get<FontGlyphPtr>(k))
222 font_glyph = *f;
223 else {
224 /* get the font (from cache if possible) */
225 FontPtr font = Font::create(ctx, file);
227 if(!font)
228 return false;
231 font_glyph = FontGlyphPtr(new FontGlyph);
234 /* get a few metrics */
235 QFontMetrics fm(font->m_font);
237 if(!fm.inFont(glyph))
238 return false;
240 int h = fm.height();
241 int w = fm.width(glyph);
242 font_glyph->m_height = h;
244 /* create the path from the char */
245 font_glyph->m_path.addText((h-w)/2, fm.ascent(), font->m_font, glyph);
247 /* save in cache */
248 ctx->put(k, font_glyph);
251 /* create lazily the inner background region */
252 if(!font_glyph->m_inner_background_init && draw_inner_bg
253 && (_bg.style() != Qt::NoBrush && !(_bg.style() <= 14 && _bg.color().alpha()==0))) {
254 //14 is the last color-based brush
256 int h = font_glyph->m_height;
257 QImage bg_img(h, h, QImage::Format_ARGB32_Premultiplied );
258 bg_img.fill( QColor(Qt::black).rgba() ); //fill all black
260 /* render the piece in blue */
261 QPainter p;
262 p.begin(&bg_img);
263 p.setBrush( Qt::blue );
264 p.setPen( Qt::NoPen);
265 p.setCompositionMode(QPainter::CompositionMode_Source);
266 p.setRenderHint(QPainter::Antialiasing, true);
267 p.drawPath(font_glyph->m_path);
268 p.end();
270 /* flood fill the connected component where blue is <192 with a transparent color */
271 ImageEffects::floodFillBlueThreshold(bg_img, QPoint(0,0), Qt::transparent, 192, true);
273 /* And we've got our region */
274 font_glyph->m_inner_background = bg_img.createAlphaMask();
275 font_glyph->m_inner_background.setColor(0, Qt::transparent);
276 font_glyph->m_inner_background_init = true;
279 /* draw the glyph, at last :) */
280 int h = font_glyph->m_height;
281 QPainter p(&m_image);
282 init_painter(&p);
284 p.translate(dest.x(), dest.y());
285 p.scale(dest.width()/h, dest.height()/h);
287 //14 is the last color-based brush
288 if(_bg.style() != Qt::NoBrush && !(_bg.style() <= 14 && _bg.color().alpha()==0)) {
289 QBrush bg = _bg;
290 QMatrix m = bg.matrix();
291 m = m * QMatrix().translate(-dest.x(), -dest.y());
292 m = m * QMatrix().scale(h/dest.width(), h/dest.height());
293 bg.setMatrix(m);
295 if(draw_inner_bg) {
296 QMatrix m = p.matrix();
297 QRectF r = m.mapRect(QRectF(0,0,h,h));
298 QRect ir = r.toRect();
299 QImage tmp(ir.size(), QImage::Format_ARGB32_Premultiplied);
300 tmp.fill(0);
302 QPainter ptmp(&tmp);
303 ptmp.setRenderHint(QPainter::Antialiasing);
304 ptmp.setRenderHint(QPainter::TextAntialiasing);
305 ptmp.setRenderHint(QPainter::SmoothPixmapTransform);
306 ptmp.translate(-ir.x(), -ir.y());
307 ptmp.setMatrix(m, true);
308 ptmp.drawImage(QRect(0,0,h,h), font_glyph->m_inner_background);
309 if(border > 0.0 || !_fg.isOpaque() ) {
310 ptmp.setBrush( _fg.isOpaque() ? QBrush(Qt::NoBrush) : QBrush(Qt::red) );
311 ptmp.setPen( (border > 0.0)
312 ? QPen( Qt::green, h*border/100.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
313 : Qt::NoPen );
314 ptmp.drawPath(font_glyph->m_path);
316 ptmp.setCompositionMode(QPainter::CompositionMode_SourceIn);
317 ptmp.fillRect(QRect(0,0,h,h), bg);
319 p.resetMatrix();
320 p.drawImage(ir, tmp);
321 p.setMatrix(m);
323 else if(border > 0.0 || !_fg.isOpaque() ) {
324 p.setBrush( _fg.isOpaque() ? Qt::NoBrush : bg );
325 p.setPen( (border > 0.0)
326 ? QPen(bg, h*border/100.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
327 : Qt::NoPen );
328 p.drawPath(font_glyph->m_path);
331 if(_fg.style() != Qt::NoBrush) {
332 QBrush fg = _fg;
333 QMatrix m = fg.matrix();
334 m = m * QMatrix().translate(-dest.x(), -dest.y());
335 m = m * QMatrix().scale(h/dest.width(), h/dest.height());
336 fg.setMatrix(m);
338 p.setBrush( fg );
339 p.setPen( Qt::NoPen );
340 p.drawPath(font_glyph->m_path);
342 return true;
346 void Image::expBlur(double radius) {
347 if(m_image.format() != QImage::Format_RGB32
348 && m_image.format() != QImage::Format_ARGB32
349 && m_image.format() != QImage::Format_ARGB32_Premultiplied)
350 m_image = m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
351 ImageEffects::expBlur(m_image, int(radius) );
355 Image Image::createShadow(double radius,
356 const QColor& color,
357 const QPoint& grow,
358 const QPointF& offset) {
359 Image retv(width()+grow.x(), height()+grow.y());
360 int px = int(grow.x()*0.5+offset.x());
361 int py = int(grow.y()*0.5+offset.y());
362 QPainter p;
364 retv.m_image.fill(0);
366 p.begin(&retv.m_image);
367 p.setCompositionMode(QPainter::CompositionMode_Source);
368 p.fillRect( QRect(px, py, width(), height()), color);
369 p.setCompositionMode(QPainter::CompositionMode_DestinationAtop );
370 p.drawImage( QPoint(px, py), m_image);
371 p.end();
373 ImageEffects::expBlur(retv.m_image, int(radius) );
374 return retv;
377 //END Image--------------------------------------------------------------------
379 //BEGIN Glyph------------------------------------------------------------------
381 Glyph::Glyph(const QString& c, int d)
382 : m_font_valid(false)
383 , m_char(c)
384 , m_delta(d) { }
386 Glyph::Glyph(Context* ctx, const QString& file, const QChar& c, int d)
387 : m_font_valid(false)
388 , m_char(c)
389 , m_delta(d) {
390 if(ctx) {
391 if(FontPtr ff = Font::create(ctx, file)) {
392 m_font_valid = true;
393 m_font = ff->m_font;
398 Glyph::Glyph(const QChar& c)
399 : m_font_valid(false)
400 , m_char(c)
401 , m_delta(0) {
405 //END Glyph--------------------------------------------------------------------
407 } //end namespace Loader