Go to the documentation of this file.
11 #include <QCoreApplication>
13 #include <QDomDocument>
16 #include <QImageReader>
17 #include <QReadWriteLock>
37 #define LOC QString("MythUIImage(0x%1): ").arg((uint64_t)this,0,16)
120 LOG(VB_GUI | VB_FILE, LOG_DEBUG,
121 QString(
"ImageLoader::PreLoad(%1), this "
122 "file is already being loaded by this same MythUIImage "
123 "in another thread.").
arg(cacheKey));
148 QString extension =
filename.section(
'.', -1);
149 return !
filename.startsWith(
"myth://") &&
150 (extension ==
"gif" ||
151 extension ==
"apng" ||
168 s_Attrib +=
"reflected";
171 s_Attrib +=
"greyscale";
175 s_Attrib +=
"orientation";
191 imagelabel = QString(
"%1-%2-%3x%4.png")
196 imagelabel.replace(
'/',
'-');
198 imagelabel.replace(
':',
'-');
216 if (!
PreLoad(cacheKey, parent))
225 bool bResize =
false;
226 bool bFoundInCache =
false;
254 LOG(VB_GUI | VB_FILE, LOG_INFO,
255 QString(
"ImageLoader::LoadImage(%1) Found in cache, "
266 bFoundInCache =
true;
270 LOG(VB_GUI | VB_FILE, LOG_INFO,
271 QString(
"ImageLoader::LoadImage(%1) NOT Found in cache. "
272 "Loading Directly").
arg(cacheKey));
278 ok = image->
Load(imageReader);
289 if (image && image->isNull())
291 LOG(VB_GUI | VB_FILE, LOG_INFO,
292 QString(
"ImageLoader::LoadImage(%1) Image is NULL")
299 if (image && !bFoundInCache)
322 if (wmult != 1.0F || hmult != 1.0F)
324 w = image->size().width() * wmult;
325 h = image->size().height() * hmult;
341 if (wmult != 1.0F || hmult != 1.0F)
343 int width = newMaskImage->size().width() * wmult;
344 int height = newMaskImage->size().height() * hmult;
345 newMaskImage->
Resize(QSize(width, height));
354 QRect imageArea = image->rect();
361 if (maskArea.width() > imageArea.width())
362 x = (maskArea.width() - imageArea.width()) / 2;
364 if (maskArea.height() > imageArea.height())
365 y = (maskArea.height() - imageArea.height()) / 2;
368 imageArea.translate(x, y);
371 image->setAlphaChannel(mask.convertToFormat(QImage::Format_Alpha8));
397 QString frameFilename;
403 while (imageReader->canRead() && !aborted)
405 frameFilename =
filename.arg(imageCount);
411 aborted, imageReader);
416 images->append(
AnimationFrame(im, imageReader->nextImageDelay()));
439 int number,
bool aborted)
478 (QEvent::Type) QEvent::registerEventType();
496 bool aborted =
false;
509 if (frames && frames->count() > 1)
514 QCoreApplication::postEvent(
m_parent, le);
529 QCoreApplication::postEvent(
m_parent, le);
557 int low,
int high,
int delayms,
624 QHash<int, MythImage *>::iterator it =
m_images.begin();
734 for (
int delay : qAsConst(delays))
765 if (!forceSize.isNull())
767 int w = (forceSize.width() <= 0) ? img->width() : forceSize.width();
768 int h = (forceSize.height() <= 0) ? img->height() : forceSize.height();
819 for (
auto *im : qAsConst(*images))
832 if (!forceSize.isNull())
834 int w = (forceSize.width() <= 0) ? im->width() : forceSize.width();
835 int h = (forceSize.height() <= 0) ? im->height() : forceSize.height();
858 aSize = aSize.expandedTo(im->size());
879 QVector<MythImage *> images;
881 for (
const auto & frame : qAsConst(frames))
883 images.append(frame.first);
884 delays.append(frame.second);
891 if (
m_delay < 0 && !delays.empty())
980 if (bFilename.isEmpty())
989 if (qEnvironmentVariableIsSet(
"DISABLETHREADEDMYTHUIIMAGE"))
990 allowLoadInBackground =
false;
1000 bool complete =
true;
1009 bFilename.contains(
"%1"))
1028 bool do_background_load =
false;
1029 if (allowLoadInBackground)
1037 do_background_load =
true;
1040 if (do_background_load)
1043 LOG(VB_GUI | VB_FILE, LOG_DEBUG,
LOC +
1044 QString(
"Load(), spawning thread to load '%1'").
arg(
filename));
1048 imProps, bFilename, i,
1054 if (!isAnimation && !
GetMythUI()->IsImageInCache(imagelabel))
1058 LOG(VB_GUI | VB_FILE, LOG_DEBUG,
LOC +
1059 QString(
"Load(), loading '%1' in foreground").
arg(
filename));
1060 bool aborted =
false;
1072 LOG(VB_GUI, LOG_DEBUG, QString(
"Aborted loading animated"
1073 "image %1 in foreground")
1093 LOG(VB_GUI, LOG_DEBUG, QString(
"Aborted loading animated"
1094 "image %1 in foreground")
1104 rect.setSize(image->size());
1130 complete &= !do_background_load;
1208 int alphaMod, QRect clipRect)
1234 area.translate(xoffset, yoffset);
1251 QRect currentImageArea = currentImage->rect();
1254 area.setSize(area.size().expandedTo(currentImage->size()));
1261 if (area.width() > visibleImage.width())
1262 x = area.width() / 2 + visibleImage.topLeft().x();
1264 if (area.height() > visibleImage.height())
1265 y = area.height() / 2 + visibleImage.topLeft().y();
1267 if ((x > 0 || y > 0))
1268 area.translate(x, y);
1276 srcRect = currentImageArea;
1278 p->SetClipRect(clipRect);
1279 p->DrawImage(area, currentImage, srcRect, alpha);
1291 const QString &
filename, QDomElement &element,
bool showWarnings)
1295 if (element.tagName() ==
"filename")
1308 else if (element.tagName() ==
"filepattern")
1312 QString
tmp = element.attribute(
"low");
1317 tmp = element.attribute(
"high");
1322 tmp = element.attribute(
"cycle",
"start");
1324 if (
tmp ==
"reverse")
1327 else if (element.tagName() ==
"area")
1332 else if (element.tagName() ==
"preserveaspect")
1334 else if (element.tagName() ==
"crop")
1336 else if (element.tagName() ==
"delay")
1340 if (value.contains(
","))
1342 QVector<int> delays;
1343 QStringList tokens = value.split(
",");
1344 for (
const auto &
token : qAsConst(tokens))
1346 if (
token.isEmpty())
1348 if (!delays.empty())
1349 delays.append(delays[delays.size()-1]);
1355 delays.append(
token.toInt());
1359 if (!delays.empty())
1370 else if (element.tagName() ==
"reflection")
1373 QString
tmp = element.attribute(
"axis");
1377 if (
tmp.toLower() ==
"horizontal")
1383 tmp = element.attribute(
"shear");
1388 tmp = element.attribute(
"scale");
1393 tmp = element.attribute(
"length");
1398 tmp = element.attribute(
"spacing");
1403 else if (element.tagName() ==
"mask")
1408 else if (element.tagName() ==
"grayscale" ||
1409 element.tagName() ==
"greyscale")
1435 LOG(VB_GENERAL, LOG_ERR,
1436 QString(
"'%1' (%2) ERROR, bad parsing '%3' (%4)")
1539 if (!le || le->GetParent() !=
this)
1543 int number = le->GetNumber();
1544 QString
filename = le->GetFilename();
1546 bool aborted = le->GetAbortState();
1559 if (aborted || (le->GetBasefile() != propFilename))
1562 LOG(VB_GUI, LOG_DEBUG, QString(
"Aborted loading image %1")
1568 if (animationFrames)
1570 for (
const auto & frame : qAsConst(*animationFrames))
1577 delete animationFrames;
1580 else if (animationFrames)
1584 delete animationFrames;
1600 rect.setSize(image->size());
1639 if (!imageDir.exists())
1645 QStringList imageTypes;
1647 QList< QByteArray > exts = QImageReader::supportedImageFormats();
1648 for (
const auto & ext : qAsConst(exts))
1650 imageTypes.append(QString(
"*.").append(ext));
1653 imageDir.setNameFilters(imageTypes);
1655 QStringList imageList = imageDir.entryList();
1658 if (!imageList.empty())
1663 uint32_t rand =
MythRandom() %
static_cast<uint32_t
>(imageList.size());
1664 randFile = QString(
"%1%2").arg(
m_imageDirectory).arg(imageList.takeAt(
static_cast<int>(rand)));
friend class MythUIImagePrivate
ImageCacheMode m_cacheMode
void SetMaskImage(MythImage *image)
bool GetAbortState() const
Image widget, displays a single image or multiple images in sequence.
ImageLoadThread(MythUIImage *parent, MythPainter *painter, const ImageProperties &imProps, QString basefile, int number, ImageCacheMode mode)
bool Load(MythImageReader *reader)
QHash< int, MythImage * > m_images
MythUIImage(const QString &filepattern, int low, int high, int delayms, MythUIType *parent, const QString &name)
QReadWriteLock m_updateLock
QHash< int, int > m_delays
MythImage * GetImage() const
virtual MythRect GetFullArea(void) const
int CalcAlpha(int alphamod) const
QRect toQRect(void) const
void Reflect(ReflectAxis axis, int shear, int scale, int length, int spacing=0)
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
static QHash< QString, const MythUIImage * > m_loadingImages
static void PostLoad(const QString &cacheKey)
static QMutex m_loadingImagesLock
arg(title).arg(filename).arg(doDelete))
virtual MythPainter * GetPainter(void)
ReflectAxis m_reflectAxis
static QString GenImageLabel(const ImageProperties &imProps)
Generates a unique identifying string for this image which is used as a key in the image cache.
ImageLoadEvent(const MythUIImage *parent, AnimationFrames *frames, QString basefile, QString filename, bool aborted)
void customEvent(QEvent *event) override
void SetOrientation(int orientation)
Saves the exif orientation value of the first image in the widget.
virtual void SetArea(const MythRect &rect)
QString GetBasefile() const
QImage GetMaskImageSubset(QRect imageArea)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QPair< MythImage *, int > AnimationFrame
AnimationFrames * GetAnimationFrames() const
void LoadNow(void) override
Cause images in this and child widgets to be loaded.
void SetFilepattern(const QString &filepattern, int low, int high)
Must be followed by a call to Load() to load the image.
void Clear(void)
Remove all images from the widget.
void Reset(void) override
Reset the image back to the default defined in the theme.
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
QVector< AnimationFrame > AnimationFrames
static QWaitCondition m_loadingImagesCond
bool m_showingRandomImage
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
void setIsOriented(bool oriented)
void SetCropRect(int x, int y, int width, int height)
Crop the image using the given rectangle, useful for removing unsightly edges from imported images or...
QString m_maskImageFilename
static bool PreLoad(const QString &cacheKey, const MythUIImage *uitype)
ImageProperties & operator=(const ImageProperties &other)
void SetSize(int width, int height)
Set the size of the widget.
QString GetXMLLocation(void) const
virtual void SetMinArea(const MythRect &rect)
Set the minimum area based on the given size.
void DependChanged(bool isDefault)
~MythUIImagePrivate()=default
void SetAnimationFrames(const AnimationFrames &frames)
void SetDelay(int delayms)
Set the delay between each image in an animation.
AnimationFrames * m_images
static QString getFirstText(QDomElement &element)
int DecrRef(void) override
Decrements reference count and deletes on 0.
void CalculateArea(QRect parentArea)
friend class ImageLoadThread
void setIsReflected(bool reflected)
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
void Copy(const ImageProperties &other)
MythImage * LoadCacheImage(QString File, const QString &Label, MythPainter *Painter, ImageCacheMode cacheMode=kCacheNormal)
static MythRect parseRect(const QString &text, bool normalize=true)
virtual void SetChanged(bool change=true)
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
void SetMaskImageFilename(const QString &filename)
static bool SupportsAnimation(const QString &filename)
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
const MythUIImage * m_parent
virtual void Reset(void)
Reset the widget to it's original state, should not reset changes made by the theme.
static AnimationFrames * LoadAnimatedImage(MythPainter *painter, const ImageProperties &imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted)
The base class on which all widgets and screens are based.
void Orientation(int orientation)
Changes the orientation angle of the image according to the exif rotation values.
bool IsDeferredLoading(bool recurse=false) const
void SetImageCount(int low, int high)
Set the integer range for an animated image pattern.
ImageProperties m_imageProperties
QString GetFilename() const
MBASE_PUBLIC uint32_t MythRandom()
int IncrRef(void) override
Increments reference count.
void SetImages(QVector< MythImage * > *images)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
QRect GetMaskImageRect(void)
virtual void LoadNow(void)
Cause images in this and child widgets to be loaded.
ImageProperties()=default
virtual void SetSize(QSize size)
void ForceSize(QSize size)
Force the dimensions of the widget and image to the given size.
MythUIImagePrivate(MythUIImage *p)
void SetDelays(const QVector< int > &delays)
Sets the delays between each image in an animation.
MythMainWindow * GetMythMainWindow(void)
void FindRandomImage(void)
QString GetMaskImageFilename()
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
ImageLoadEvent(const MythUIImage *parent, MythImage *image, QString basefile, QString filename, int number, bool aborted)
void Resize(QSize newSize, bool preserveAspect=false)
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
void Finalize(void) override
Perform any post-xml parsing initialisation tasks.
ImageProperties m_imageProperties
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
MythUIHelper * GetMythUI()
void GetScalingFactors(float &Horizontal, float &Vertical) const
AnimationCycle m_animationCycle
static bool parseBool(const QString &text)
QRect GetExtent(QSize size) const
static MythImage * LoadImage(MythPainter *painter, ImageProperties imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted, MythImageReader *imageReader=nullptr)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
MThreadPool * GetImageThreadPool()
const MythUIImage * GetParent() const
MythImage * CacheImage(const QString &URL, MythImage *Image, bool NoDisk=false)
QString GetFileName(void) const
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override