not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / wallpapers / image / renderthread.cpp
blob22f3a77b75c1a3516c3ae4187b65fe754e251341
1 /*
2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 */
10 #include "renderthread.h"
12 #include <QPainter>
13 #include <QFile>
14 #include <KDebug>
15 #include <KSvgRenderer>
17 RenderThread::RenderThread()
18 : m_current_token(-1)
19 , m_size(0, 0)
20 , m_ratio(1.0)
22 m_abort = false;
23 m_restart = false;
26 RenderThread::~RenderThread()
29 // abort computation
30 QMutexLocker lock(&m_mutex);
31 m_abort = true;
32 m_condition.wakeOne();
35 wait();
38 void RenderThread::setSize(const QSize& size)
40 QMutexLocker lock(&m_mutex);
41 m_size = size;
44 void RenderThread::setRatio(float ratio)
46 QMutexLocker lock(&m_mutex);
47 m_ratio = ratio;
50 int RenderThread::render(const QString &file,
51 const QColor &color,
52 Background::ResizeMethod method,
53 Qt::TransformationMode mode)
55 int token;
57 QMutexLocker lock(&m_mutex);
58 m_file = file;
59 m_color = color;
60 m_method = method;
61 m_mode = mode;
62 m_restart = true;
63 token = ++m_current_token;
66 if (!isRunning()) {
67 start();
69 else {
70 m_condition.wakeOne();
73 return token;
76 void RenderThread::run()
78 QString file;
79 QColor color;
80 QSize size;
81 float ratio;
82 Background::ResizeMethod method;
83 Qt::TransformationMode mode;
84 int token;
86 forever {
88 QMutexLocker lock(&m_mutex);
90 while (!m_restart && !m_abort) {
91 m_condition.wait(&m_mutex);
94 if (m_abort) {
95 return;
98 m_restart = false;
100 // load all parameters in nonshared variables
101 token = m_current_token;
102 file = m_file;
103 color = m_color;
104 size = m_size;
105 ratio = m_ratio;
106 method = m_method;
107 mode = m_mode;
110 QImage result(size, QImage::Format_ARGB32_Premultiplied);
111 result.fill(color.rgba());
113 if (file.isEmpty() || !QFile::exists(file)) {
114 emit done(token, result);
115 continue;
118 QPoint pos(0, 0);
119 bool tiled = false;
120 bool scalable = file.endsWith("svg") || file.endsWith("svgz");
121 QSize scaledSize;
122 QImage img;
124 // set image size
125 QSize imgSize;
126 if (scalable) {
127 // scalable: image can be of any size
128 imgSize = size;
129 } else {
130 // otherwise, use the natural size of the loaded image
131 img = QImage(file);
132 imgSize = img.size();
133 kDebug() << "loaded with" << imgSize << ratio;
136 // if any of them is zero we may run into a div-by-zero below.
137 if (imgSize.width() < 1) {
138 imgSize.setWidth(1);
141 if (imgSize.height() < 1) {
142 imgSize.setHeight(1);
145 // set render parameters according to resize mode
146 switch (method)
148 case Background::Scale:
149 imgSize *= ratio;
150 scaledSize = size;
151 break;
152 case Background::Center:
153 scaledSize = imgSize;
154 pos = QPoint((size.width() - scaledSize.width()) / 2,
155 (size.height() - scaledSize.height()) / 2);
157 //If the picture is bigger than the screen, shrink it
158 if (size.width() < imgSize.width() && imgSize.width() > imgSize.height()) {
159 int width = size.width();
160 int height = width * scaledSize.height() / imgSize.width();
161 scaledSize = QSize(width, height);
162 pos = QPoint((size.width() - scaledSize.width()) / 2,
163 (size.height() - scaledSize.height()) / 2);
164 } else if (size.height() < imgSize.height()) {
165 int height = size.height();
166 int width = height * imgSize.width() / imgSize.height();
167 scaledSize = QSize(width, height);
168 pos = QPoint((size.width() - scaledSize.width()) / 2,
169 (size.height() - scaledSize.height()) / 2);
172 break;
173 case Background::Maxpect: {
174 imgSize *= ratio;
175 float xratio = (float) size.width() / imgSize.width();
176 float yratio = (float) size.height() / imgSize.height();
177 if (xratio > yratio) {
178 int height = size.height();
179 int width = height * imgSize.width() / imgSize.height();
180 scaledSize = QSize(width, height);
181 } else {
182 int width = size.width();
183 int height = width * imgSize.height() / imgSize.width();
184 scaledSize = QSize(width, height);
186 pos = QPoint((size.width() - scaledSize.width()) / 2,
187 (size.height() - scaledSize.height()) / 2);
188 break;
190 case Background::ScaleCrop: {
191 imgSize *= ratio;
192 float xratio = (float) size.width() / imgSize.width();
193 float yratio = (float) size.height() / imgSize.height();
194 if (xratio > yratio) {
195 int width = size.width();
196 int height = width * imgSize.height() / imgSize.width();
197 scaledSize = QSize(width, height);
198 } else {
199 int height = size.height();
200 int width = height * imgSize.width() / imgSize.height();
201 scaledSize = QSize(width, height);
203 pos = QPoint((size.width() - scaledSize.width()) / 2,
204 (size.height() - scaledSize.height()) / 2);
205 break;
207 case Background::Tiled:
208 scaledSize = imgSize;
209 tiled = true;
210 break;
211 case Background::CenterTiled:
212 scaledSize = imgSize;
213 pos = QPoint(
214 -scaledSize.width() +
215 ((size.width() - scaledSize.width()) / 2) % scaledSize.width(),
216 -scaledSize.height() +
217 ((size.height() - scaledSize.height()) / 2) % scaledSize.height());
218 tiled = true;
219 break;
222 QPainter p(&result);
223 kDebug() << token << scalable << scaledSize << imgSize;
224 if (scalable) {
225 // tiling is ignored for scalable wallpapers
226 KSvgRenderer svg(file);
227 if (m_restart) {
228 continue;
230 svg.render(&p);
231 } else {
232 if (scaledSize != imgSize) {
233 img = img.scaled(scaledSize, Qt::IgnoreAspectRatio, mode);
236 if (m_restart) {
237 continue;
240 if (tiled) {
241 for (int x = pos.x(); x < size.width(); x += scaledSize.width()) {
242 for (int y = pos.y(); y < size.height(); y += scaledSize.height()) {
243 p.drawImage(QPoint(x, y), img);
244 if (m_restart) {
245 goto endLoop;
249 } else {
250 p.drawImage(pos, img);
254 // signal we're done
255 emit done(token, result);
256 endLoop: continue;