00001
00002
00003 #include "mythimage.h"
00004
00005
00006 #include <stdint.h>
00007
00008
00009 #include <QImageReader>
00010 #include <QPainter>
00011 #include <QMatrix>
00012 #include <QNetworkReply>
00013 #include <QRgb>
00014
00015
00016 #include "mythdownloadmanager.h"
00017 #include "mythlogging.h"
00018
00019
00020 #include "remotefile.h"
00021
00022
00023 #include "mythuihelper.h"
00024 #include "mythmainwindow.h"
00025
00026 MythUIHelper *MythImage::m_ui = NULL;
00027
00028 MythImage::MythImage(MythPainter *parent)
00029 {
00030 if (!parent)
00031 LOG(VB_GENERAL, LOG_ERR, "Image created without parent!");
00032
00033 m_Parent = parent;
00034 m_RefCount = 0;
00035
00036 m_Changed = false;
00037
00038 m_isGradient = false;
00039 m_gradBegin = QColor("#000000");
00040 m_gradEnd = QColor("#FFFFFF");
00041 m_gradAlpha = 255;
00042 m_gradDirection = FillTopToBottom;
00043
00044 m_isReflected = false;
00045 m_isYUV = false;
00046
00047 m_imageId = 0;
00048
00049 m_FileName = "";
00050
00051 m_cached = false;
00052 if (!m_ui)
00053 m_ui = GetMythUI();
00054 }
00055
00056 MythImage::~MythImage()
00057 {
00058 if (m_Parent)
00059 m_Parent->DeleteFormatImage(this);
00060 }
00061
00062 void MythImage::UpRef(void)
00063 {
00064 QMutexLocker locker(&m_RefCountLock);
00065 if (m_ui && m_cached && m_RefCount == 1)
00066 m_ui->ExcludeFromCacheSize(this);
00067 m_RefCount++;
00068 }
00069
00070 bool MythImage::DownRef(void)
00071 {
00072 m_RefCountLock.lock();
00073 m_RefCount--;
00074 if (m_ui && m_cached)
00075 {
00076 if (m_RefCount == 1)
00077 m_ui->IncludeInCacheSize(this);
00078 else if (m_RefCount == 0)
00079 m_ui->ExcludeFromCacheSize(this);
00080 }
00081
00082 if (m_RefCount <= 0)
00083 {
00084 m_RefCountLock.unlock();
00085 delete this;
00086 return true;
00087 }
00088 m_RefCountLock.unlock();
00089 return false;
00090 }
00091
00092 int MythImage::RefCount(void)
00093 {
00094 QMutexLocker locker(&m_RefCountLock);
00095 return m_RefCount;
00096 }
00097
00098 void MythImage::SetIsInCache(bool bCached)
00099 {
00100 QMutexLocker locker(&m_RefCountLock);
00101 if (m_ui && m_RefCount == 1)
00102 {
00103 if (!m_cached && bCached)
00104 m_ui->IncludeInCacheSize(this);
00105 else if (m_cached && !bCached)
00106 m_ui->ExcludeFromCacheSize(this);
00107 }
00108 m_cached = bCached;
00109 }
00110
00111 void MythImage::Assign(const QImage &img)
00112 {
00113 QMutexLocker locker(&m_RefCountLock);
00114 if (m_ui && m_RefCount == 1 && m_cached)
00115 m_ui->ExcludeFromCacheSize(this);
00116 *(static_cast<QImage *> (this)) = img;
00117 if (m_ui && m_RefCount == 1 && m_cached)
00118 m_ui->IncludeInCacheSize(this);
00119 SetChanged();
00120 }
00121
00122 void MythImage::Assign(const QPixmap &pix)
00123 {
00124 Assign(pix.toImage());
00125 }
00126
00127 void MythImage::Resize(const QSize &newSize, bool preserveAspect)
00128 {
00129 if ((size() == newSize) && !isNull())
00130 return;
00131
00132 if (m_isGradient)
00133 {
00134 *(static_cast<QImage *> (this)) = QImage(newSize, QImage::Format_ARGB32);
00135 MakeGradient(*this, m_gradBegin, m_gradEnd, m_gradAlpha, m_gradDirection);
00136 SetChanged();
00137 }
00138 else
00139 {
00140 Qt::AspectRatioMode mode = Qt::IgnoreAspectRatio;
00141 if (preserveAspect)
00142 mode = Qt::KeepAspectRatio;
00143
00144 Assign(scaled(newSize, mode, Qt::SmoothTransformation));
00145 }
00146 }
00147
00148 void MythImage::Reflect(ReflectAxis axis, int shear, int scale, int length,
00149 int spacing)
00150 {
00151 if (m_isReflected)
00152 return;
00153
00154 QImage mirrorImage;
00155 FillDirection fillDirection = FillTopToBottom;
00156 if (axis == ReflectVertical)
00157 {
00158 mirrorImage = mirrored(false,true);
00159 if (length < 100)
00160 {
00161 int height = (int)((float)mirrorImage.height() * (float)length/100);
00162 mirrorImage = mirrorImage.copy(0,0,mirrorImage.width(),height);
00163 }
00164 fillDirection = FillTopToBottom;
00165 }
00166 else if (axis == ReflectHorizontal)
00167 {
00168 mirrorImage = mirrored(true,false);
00169 if (length < 100)
00170 {
00171 int width = (int)((float)mirrorImage.width() * (float)length/100);
00172 mirrorImage = mirrorImage.copy(0,0,width,mirrorImage.height());
00173 }
00174 fillDirection = FillLeftToRight;
00175 }
00176
00177 QImage alphaChannel(mirrorImage.size(), QImage::Format_ARGB32);
00178 MakeGradient(alphaChannel, QColor("#AAAAAA"), QColor("#000000"), 255,
00179 false, fillDirection);
00180 mirrorImage.setAlphaChannel(alphaChannel);
00181
00182 QMatrix shearMatrix;
00183 if (axis == ReflectVertical)
00184 {
00185 shearMatrix.scale(1,(float)scale/100);
00186 shearMatrix.shear((float)shear/100,0);
00187 }
00188 else if (axis == ReflectHorizontal)
00189 {
00190 shearMatrix.scale((float)scale/100,1);
00191 shearMatrix.shear(0,(float)shear/100);
00192 }
00193
00194 mirrorImage = mirrorImage.transformed(shearMatrix, Qt::SmoothTransformation);
00195
00196 QSize newsize;
00197 if (axis == ReflectVertical)
00198 newsize = QSize(mirrorImage.width(), height()+spacing+mirrorImage.height());
00199 else if (axis == ReflectHorizontal)
00200 newsize = QSize(width()+spacing+mirrorImage.width(), mirrorImage.height());
00201
00202 QImage temp(newsize, QImage::Format_ARGB32);
00203 temp.fill(Qt::transparent);
00204
00205 QPainter newpainter(&temp);
00206 newpainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
00207 if (axis == ReflectVertical)
00208 {
00209 if (shear < 0)
00210 newpainter.drawImage(mirrorImage.width()-width(), 0,
00211 copy(0,0,width(),height()));
00212 else
00213 newpainter.drawImage(0, 0, copy(0,0,width(),height()));
00214
00215 newpainter.drawImage(0, height()+spacing, mirrorImage);
00216 }
00217 else if (axis == ReflectHorizontal)
00218 {
00219 if (shear < 0)
00220 newpainter.drawImage(0, mirrorImage.height()-height(),
00221 copy(0,0,width(),height()));
00222 else
00223 newpainter.drawImage(0, 0, copy(0,0,width(),height()));
00224
00225 newpainter.drawImage(width()+spacing, 0, mirrorImage);
00226 }
00227
00228 newpainter.end();
00229
00230 Assign(temp);
00231
00232 m_isReflected = true;
00233 }
00234
00235 void MythImage::ToGreyscale()
00236 {
00237 if (isGrayscale())
00238 return;
00239
00240 for (int y = 0; y < height(); ++y)
00241 {
00242 for (int x = 0; x < width(); ++x)
00243 {
00244 QRgb oldPixel = pixel(x, y);
00245 int greyVal = qGray(oldPixel);
00246 setPixel(x, y, qRgba(greyVal, greyVal, greyVal, qAlpha(oldPixel)));
00247 }
00248 }
00249 }
00250
00251 bool MythImage::Load(MythImageReader *reader)
00252 {
00253 if (!reader || !reader->canRead())
00254 return false;
00255
00256 QImage *im = new QImage;
00257
00258 if (im && reader->read(im))
00259 {
00260 Assign(*im);
00261 delete im;
00262 return true;
00263 }
00264
00265 if (im)
00266 delete im;
00267
00268 return false;
00269 }
00270
00271
00272 bool MythImage::Load(const QString &filename, bool scale)
00273 {
00274 QImage *im = NULL;
00275 if (scale)
00276 im = GetMythUI()->LoadScaleImage(filename);
00277 else
00278 {
00279 if (filename.startsWith("myth://"))
00280 {
00281 im = new QImage();
00282 RemoteFile *rf = new RemoteFile(filename, false, false, 0);
00283
00284 QByteArray data;
00285 bool ret = rf->SaveAs(data);
00286
00287 delete rf;
00288
00289 if (ret)
00290 im->loadFromData(data);
00291 #if 0
00292 else
00293 LOG(VB_GENERAL, LOG_ERR,
00294 QString("MythImage::Load failed to load remote image %1")
00295 .arg(filename));
00296 #endif
00297
00298 }
00299 else if ((filename.startsWith("http://")) ||
00300 (filename.startsWith("https://")) ||
00301 (filename.startsWith("ftp://")))
00302 {
00303 im = new QImage();
00304 QByteArray data;
00305 if (GetMythDownloadManager()->download(filename, &data))
00306 im->loadFromData(data);
00307 }
00308 else
00309 {
00310 im = new QImage(filename);
00311 }
00312 }
00313
00314 SetFileName(filename);
00315 if (im)
00316 {
00317 Assign(*im);
00318 delete im;
00319 return true;
00320 }
00321
00322 return false;
00323 }
00324
00325 void MythImage::MakeGradient(QImage &image, const QColor &begin,
00326 const QColor &end, int alpha, bool drawBoundary,
00327 FillDirection direction)
00328 {
00329
00330 QColor startColor = begin;
00331 QColor endColor = end;
00332 startColor.setAlpha(alpha);
00333 endColor.setAlpha(alpha);
00334
00335
00336 QPoint pointA(0,0);
00337 QPoint pointB;
00338 if (direction == FillTopToBottom)
00339 {
00340 pointB = QPoint(0,image.height());
00341 }
00342 else if (direction == FillLeftToRight)
00343 {
00344 pointB = QPoint(image.width(),0);
00345 }
00346
00347 QLinearGradient gradient(pointA, pointB);
00348 gradient.setColorAt(0, startColor);
00349 gradient.setColorAt(1, endColor);
00350
00351
00352 QPainter painter(&image);
00353 painter.setCompositionMode(QPainter::CompositionMode_Source);
00354 painter.fillRect(0, 0, image.width(), image.height(), gradient);
00355
00356 if (drawBoundary)
00357 {
00358
00359 QColor black(0, 0, 0, alpha);
00360 painter.setPen(black);
00361 QPen pen = painter.pen();
00362 pen.setWidth(1);
00363 painter.drawRect(image.rect());
00364 }
00365 painter.end();
00366 }
00367
00368 MythImage *MythImage::Gradient(MythPainter *painter,
00369 const QSize & size, const QColor &begin,
00370 const QColor &end, uint alpha,
00371 FillDirection direction)
00372 {
00373 QImage img(size.width(), size.height(), QImage::Format_ARGB32);
00374
00375 MakeGradient(img, begin, end, alpha, true, direction);
00376
00377 MythImage *ret = painter->GetFormatImage();
00378 ret->Assign(img);
00379 ret->m_isGradient = true;
00380 ret->m_gradBegin = begin;
00381 ret->m_gradEnd = end;
00382 ret->m_gradAlpha = alpha;
00383 ret->m_gradDirection = direction;
00384 return ret;
00385 }
00386
00387 #define SCALEBITS 8
00388 #define ONE_HALF (1 << (SCALEBITS - 1))
00389 #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) ))
00390
00391 void MythImage::ConvertToYUV(void)
00392 {
00393 if (m_isYUV)
00394 return;
00395
00396 m_isYUV = true;
00397
00398 int r, r1, g, g1, b, b1, a;
00399 for (int i = 0; i < height(); i ++)
00400 {
00401 QRgb *data = (QRgb*)scanLine(i);
00402 for (int j = 0; j < width(); j++)
00403 {
00404 r = qRed(data[j]);
00405 g = qGreen(data[j]);
00406 b = qBlue(data[j]);
00407 a = qAlpha(data[j]);
00408
00409 r1 = (FIX(0.299) * r + FIX(0.587) * g +
00410 FIX(0.114) * b + ONE_HALF) >> SCALEBITS;
00411 g1 = ((- FIX(0.169) * r - FIX(0.331) * g +
00412 FIX(0.499) * b + ONE_HALF) >> SCALEBITS) + 128;
00413 b1 = ((FIX(0.499) * r - FIX(0.418) * g -
00414 FIX(0.0813) * b + ONE_HALF) >> SCALEBITS) + 128;
00415
00416 data[j] = qRgba(r1, g1, b1, a);
00417 }
00418 }
00419 }
00420
00421 MythImageReader::MythImageReader(const QString &fileName)
00422 : QImageReader(),
00423 m_fileName(fileName), m_networkReply(NULL)
00424 {
00425 if ((m_fileName.startsWith("http://")) ||
00426 (m_fileName.startsWith("https://")) ||
00427 (m_fileName.startsWith("ftp://")))
00428 {
00429 m_networkReply = GetMythDownloadManager()->download(m_fileName);
00430 if (m_networkReply)
00431 setDevice(m_networkReply);
00432 }
00433 else if (!m_fileName.isEmpty())
00434 {
00435 if (!m_fileName.startsWith("/") && !QFile::exists(m_fileName))
00436 {
00437 QString tmpFile = GetMythUI()->GetThemeDir() + '/' + m_fileName;
00438 if (QFile::exists(tmpFile))
00439 m_fileName = tmpFile;
00440 }
00441 setFileName(m_fileName);
00442 }
00443 }
00444
00445 MythImageReader::~MythImageReader()
00446 {
00447 if (m_networkReply)
00448 {
00449 setDevice(NULL);
00450 m_networkReply->deleteLater();
00451 m_networkReply = NULL;
00452 }
00453 }
00454