mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 15:58:31 +00:00
initial commit version 0.0.1
This commit is contained in:
174
libcore/fontmanager.c
Normal file
174
libcore/fontmanager.c
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "fontmanager.h"
|
||||
#include "../config.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
using namespace std;
|
||||
|
||||
cMutex cFontManager::mutex;
|
||||
|
||||
cFontManager::cFontManager() {
|
||||
}
|
||||
|
||||
cFontManager::~cFontManager() {
|
||||
DeleteFonts();
|
||||
}
|
||||
|
||||
void cFontManager::CacheFonts(cTemplate *tpl) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
vector< pair<string, int> > usedFonts = tpl->GetUsedFonts();
|
||||
|
||||
cStringList availableFonts;
|
||||
cFont::GetAvailableFontNames(&availableFonts);
|
||||
|
||||
for (vector< pair<string, int> >::iterator ft = usedFonts.begin(); ft != usedFonts.end(); ft++) {
|
||||
string fontName = ft->first;
|
||||
int fontSize = ft->second;
|
||||
if (fontSize < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int fontAvailable = availableFonts.Find(fontName.c_str());
|
||||
if (fontAvailable == -1) {
|
||||
esyslog("skindesigner: font %s not available, skipping", fontName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
InsertFont(fontName, fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::Debug(void) {
|
||||
dsyslog("skindesigner: fontmanager fonts available:");
|
||||
for (map < string, map< int, cFont* > >::iterator fts = fonts.begin(); fts != fonts.end(); fts++) {
|
||||
dsyslog("skindesigner: FontName %s", fts->first.c_str());
|
||||
for (map<int, cFont*>::iterator ftSizes = (fts->second).begin(); ftSizes != (fts->second).end(); ftSizes++) {
|
||||
int confHeight = ftSizes->first;
|
||||
int realHeight = (ftSizes->second)->Height();
|
||||
dsyslog("skindesigner: fontSize %d, fontHeight %d, ratio %f", confHeight, realHeight, (double)confHeight / (double)realHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::ListAvailableFonts(void) {
|
||||
cStringList availableFonts;
|
||||
cFont::GetAvailableFontNames(&availableFonts);
|
||||
int numFonts = availableFonts.Size();
|
||||
esyslog("skindesigner: %d Fonts available:", numFonts);
|
||||
for (int i=0; i<numFonts; i++) {
|
||||
esyslog("skindesigner: font %d: %s", i, availableFonts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cFontManager::DeleteFonts() {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
for(map<string, map<int,cFont*> >::iterator it = fonts.begin(); it != fonts.end(); it++) {
|
||||
for(map<int,cFont*>::iterator it2 = (it->second).begin(); it2 != (it->second).end(); it2++) {
|
||||
delete it2->second;
|
||||
}
|
||||
}
|
||||
fonts.clear();
|
||||
}
|
||||
|
||||
int cFontManager::Width(string fontName, int fontSize, const char *text) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!text)
|
||||
return 0;
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
if (!font)
|
||||
return 0;
|
||||
int width = font->Width(text);
|
||||
return width;
|
||||
}
|
||||
|
||||
int cFontManager::Height(string fontName, int fontSize) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
if (!font)
|
||||
return 0;
|
||||
return font->Height();
|
||||
}
|
||||
|
||||
cFont *cFontManager::Font(string fontName, int fontSize) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *font = GetFont(fontName, fontSize);
|
||||
//if not already cached, load it new
|
||||
if (!font)
|
||||
InsertFont(fontName, fontSize);
|
||||
font = GetFont(fontName, fontSize);
|
||||
return font;
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Private Functions
|
||||
********************************************************************************/
|
||||
|
||||
cFont *cFontManager::CreateFont(string name, int size) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
cFont *fontTmp = cFont::CreateFont(name.c_str(), size);
|
||||
if (!fontTmp)
|
||||
fontTmp = cFont::CreateFont(Setup.FontOsd, size);
|
||||
int realHeight = fontTmp->Height();
|
||||
delete fontTmp;
|
||||
cFont *font = cFont::CreateFont(name.c_str(), (double)size / (double)realHeight * (double)size);
|
||||
if (!font)
|
||||
font = cFont::CreateFont(Setup.FontOsd, (double)size / (double)realHeight * (double)size);
|
||||
return font;
|
||||
}
|
||||
|
||||
void cFontManager::InsertFont(string name, int size) {
|
||||
cFont *newFont = CreateFont(name, size);
|
||||
if (!newFont)
|
||||
return;
|
||||
map < string, map< int, cFont* > >::iterator hit = fonts.find(name);
|
||||
if (hit != fonts.end()) {
|
||||
(hit->second).insert(pair<int, cFont*>(size, newFont));
|
||||
} else {
|
||||
map<int, cFont*> fontsizes;
|
||||
fontsizes.insert(pair<int, cFont*>(size, newFont));
|
||||
fonts.insert(pair<string, map<int, cFont*> >(name, fontsizes));
|
||||
}
|
||||
}
|
||||
|
||||
cFont *cFontManager::GetFont(string name, int size) {
|
||||
map< string, map<int,cFont*> >::iterator hitName = fonts.find(name);
|
||||
if (hitName == fonts.end())
|
||||
return NULL;
|
||||
map<int,cFont*>::iterator hitSize = (hitName->second).find(size);
|
||||
if (hitSize == (hitName->second).end())
|
||||
return NULL;
|
||||
return hitSize->second;
|
||||
}
|
||||
|
||||
int cFontManager::GetFontHeight(const char *name, int height, int charWidth) {
|
||||
FT_Library library;
|
||||
FT_Face face;
|
||||
cString fontFileName = cFont::GetFontFileName(name);
|
||||
|
||||
int descender = 0;
|
||||
int y_ppem = 0;
|
||||
int error = FT_Init_FreeType(&library);
|
||||
if (error) return 0;
|
||||
error = FT_New_Face(library, fontFileName, 0, &face);
|
||||
if (error) return 0;
|
||||
error = FT_Set_Char_Size(face, charWidth * 64, height * 64, 0, 0);
|
||||
if (error) return 0;
|
||||
|
||||
descender = face->size->metrics.descender/64;
|
||||
y_ppem = face->size->metrics.y_ppem;
|
||||
int realHeight = y_ppem + descender;
|
||||
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
return realHeight;
|
||||
}
|
35
libcore/fontmanager.h
Normal file
35
libcore/fontmanager.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __FONTMANAGER_H
|
||||
#define __FONTMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <vdr/skins.h>
|
||||
|
||||
#include "../libtemplate/template.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class cFontManager {
|
||||
private:
|
||||
static cMutex mutex;
|
||||
map < string, map< int, cFont* > > fonts;
|
||||
cFont *CreateFont(string name, int size);
|
||||
void InsertFont(string name, int size);
|
||||
cFont *GetFont(string name, int size);
|
||||
int GetFontHeight(const char *name, int height, int charWidth = 0);
|
||||
public:
|
||||
cFontManager();
|
||||
~cFontManager();
|
||||
void Lock(void) { mutex.Lock(); };
|
||||
void Unlock(void) { mutex.Unlock(); };
|
||||
void CacheFonts(cTemplate *tpl);
|
||||
void DeleteFonts(void);
|
||||
int Width(string fontName, int fontSize, const char *text);
|
||||
int Height(string fontName, int fontSize);
|
||||
cFont *Font(string fontName, int fontSize);
|
||||
void Debug(void);
|
||||
void ListAvailableFonts(void);
|
||||
};
|
||||
|
||||
#endif //__FONTMANAGER_H
|
155
libcore/helpers.c
Normal file
155
libcore/helpers.c
Normal file
@@ -0,0 +1,155 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "helpers.h"
|
||||
#include <vdr/skins.h>
|
||||
|
||||
cPlugin *GetScraperPlugin(void) {
|
||||
static cPlugin *pScraper = cPluginManager::GetPlugin("scraper2vdr");
|
||||
if( !pScraper ) // if it doesn't exit, try tvscraper
|
||||
pScraper = cPluginManager::GetPlugin("tvscraper");
|
||||
return pScraper;
|
||||
}
|
||||
|
||||
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal) {
|
||||
int width = 1;
|
||||
int height = 1;
|
||||
|
||||
if ((widthMax == 0)||(heightMax==0)||(widthOriginal==0)||(heightOriginal==0))
|
||||
return cSize(width, height);
|
||||
|
||||
if ((widthOriginal <= widthMax) && (heightOriginal <= heightMax)) {
|
||||
width = widthOriginal;
|
||||
height = heightOriginal;
|
||||
} else if ((widthOriginal > widthMax) && (heightOriginal <= heightMax)) {
|
||||
width = widthMax;
|
||||
height = (double)width/(double)widthOriginal * heightOriginal;
|
||||
} else if ((widthOriginal <= widthMax) && (heightOriginal > heightMax)) {
|
||||
height = heightMax;
|
||||
width = (double)height/(double)heightOriginal * widthOriginal;
|
||||
} else {
|
||||
width = widthMax;
|
||||
height = (double)width/(double)widthOriginal * heightOriginal;
|
||||
if (height > heightMax) {
|
||||
height = heightMax;
|
||||
width = (double)height/(double)heightOriginal * widthOriginal;
|
||||
}
|
||||
}
|
||||
return cSize(width, height);
|
||||
}
|
||||
|
||||
int Minimum(int a, int b, int c, int d, int e, int f) {
|
||||
int min = a;
|
||||
if (b < min) min = b;
|
||||
if (c < min) min = c;
|
||||
if (d < min) min = d;
|
||||
if (e < min) min = e;
|
||||
if (f < min) min = f;
|
||||
return min;
|
||||
}
|
||||
|
||||
string CutText(string &text, int width, string fontName, int fontSize) {
|
||||
if (width <= fontManager->Font(fontName, fontSize)->Size())
|
||||
return text.c_str();
|
||||
cTextWrapper twText;
|
||||
twText.Set(text.c_str(), fontManager->Font(fontName, fontSize), width);
|
||||
string cuttedTextNative = twText.GetLine(0);
|
||||
stringstream sstrText;
|
||||
sstrText << cuttedTextNative << "...";
|
||||
string cuttedText = sstrText.str();
|
||||
int actWidth = fontManager->Width(fontName, fontSize, cuttedText.c_str());
|
||||
if (actWidth > width) {
|
||||
int overlap = actWidth - width;
|
||||
int charWidth = fontManager->Width(fontName, fontSize, ".");
|
||||
if (charWidth == 0)
|
||||
charWidth = 1;
|
||||
int cutChars = overlap / charWidth;
|
||||
if (cutChars > 0) {
|
||||
cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
|
||||
stringstream sstrText2;
|
||||
sstrText2 << cuttedTextNative << "...";
|
||||
cuttedText = sstrText2.str();
|
||||
}
|
||||
}
|
||||
return cuttedText;
|
||||
}
|
||||
|
||||
|
||||
string StrToLowerCase(string str) {
|
||||
string lowerCase = str;
|
||||
const int length = lowerCase.length();
|
||||
for(int i=0; i < length; ++i) {
|
||||
lowerCase[i] = std::tolower(lowerCase[i]);
|
||||
}
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
bool isNumber(const string& s) {
|
||||
string::const_iterator it = s.begin();
|
||||
while (it != s.end() && std::isdigit(*it)) ++it;
|
||||
return !s.empty() && it == s.end();
|
||||
}
|
||||
|
||||
bool FileExists(const string &path, const string &name, const string &ext) {
|
||||
stringstream fileName;
|
||||
fileName << path << name << "." << ext;
|
||||
struct stat buffer;
|
||||
return (stat (fileName.str().c_str(), &buffer) == 0);
|
||||
}
|
||||
|
||||
bool FirstFileInFolder(string &path, string &extension, string &fileName) {
|
||||
DIR *folder = NULL;
|
||||
struct dirent *file;
|
||||
folder = opendir(path.c_str());
|
||||
if (!folder)
|
||||
return false;
|
||||
while (file = readdir(folder)) {
|
||||
if (endswith(file->d_name, extension.c_str())) {
|
||||
string currentFileName = file->d_name;
|
||||
int strlength = currentFileName.size();
|
||||
if (strlength < 8)
|
||||
continue;
|
||||
fileName = currentFileName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// split: receives a char delimiter; returns a vector of strings
|
||||
// By default ignores repeated delimiters, unless argument rep == 1.
|
||||
vector<string>& splitstring::split(char delim, int rep) {
|
||||
if (!flds.empty()) flds.clear(); // empty vector if necessary
|
||||
string work = data();
|
||||
string buf = "";
|
||||
int i = 0;
|
||||
while (i < work.length()) {
|
||||
if (work[i] != delim)
|
||||
buf += work[i];
|
||||
else if (rep == 1) {
|
||||
flds.push_back(buf);
|
||||
buf = "";
|
||||
} else if (buf.length() > 0) {
|
||||
flds.push_back(buf);
|
||||
buf = "";
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!buf.empty())
|
||||
flds.push_back(buf);
|
||||
return flds;
|
||||
}
|
||||
|
||||
cStopWatch::cStopWatch(void) {
|
||||
start = cTimeMs::Now();
|
||||
last = start;
|
||||
}
|
||||
|
||||
void cStopWatch::Report(const char* message) {
|
||||
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - last));
|
||||
last = cTimeMs::Now();
|
||||
}
|
||||
|
||||
void cStopWatch::Stop(const char* message) {
|
||||
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - start));
|
||||
}
|
35
libcore/helpers.h
Normal file
35
libcore/helpers.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __HELPERS_H
|
||||
#define __HELPERS_H
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/plugin.h>
|
||||
#include "../config.h"
|
||||
|
||||
cPlugin *GetScraperPlugin(void);
|
||||
|
||||
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal);
|
||||
int Minimum(int a, int b, int c, int d, int e, int f);
|
||||
std::string CutText(string &text, int width, string fontName, int fontSize);
|
||||
std::string StrToLowerCase(string str);
|
||||
bool isNumber(const string& s);
|
||||
bool FileExists(const string &path, const string &name, const string &ext);
|
||||
bool FirstFileInFolder(string &path, string &extension, string &fileName);
|
||||
|
||||
class splitstring : public std::string {
|
||||
std::vector<std::string> flds;
|
||||
public:
|
||||
splitstring(const char *s) : std::string(s) { };
|
||||
std::vector<std::string>& split(char delim, int rep=0);
|
||||
};
|
||||
|
||||
class cStopWatch {
|
||||
private:
|
||||
uint64_t start;
|
||||
uint64_t last;
|
||||
public:
|
||||
cStopWatch(void);
|
||||
~cStopWatch(void) {};
|
||||
void Report(const char* message);
|
||||
void Stop(const char* message);
|
||||
};
|
||||
#endif // __HELPERS_H
|
389
libcore/imagecache.c
Normal file
389
libcore/imagecache.c
Normal file
@@ -0,0 +1,389 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include "imagecache.h"
|
||||
#include "../config.h"
|
||||
#include "helpers.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
cMutex cImageCache::mutex;
|
||||
|
||||
string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
|
||||
"OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
|
||||
|
||||
cImageCache::cImageCache() : cImageMagickWrapper() {
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
|
||||
cImageCache::~cImageCache() {
|
||||
Clear();
|
||||
if (tempStaticLogo) {
|
||||
delete tempStaticLogo;
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::CacheLogo(int width, int height) {
|
||||
if (config.numLogosPerSizeInitial == 0)
|
||||
return;
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
int channelsCached = 0;
|
||||
|
||||
for (const cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
|
||||
if (channelsCached >= config.numLogosPerSizeInitial)
|
||||
break;
|
||||
if (channel->GroupSep()) {
|
||||
continue;
|
||||
}
|
||||
bool success = LoadLogo(channel);
|
||||
if (success) {
|
||||
channelsCached++;
|
||||
cImage *image = CreateImage(width, height);
|
||||
stringstream logoName;
|
||||
logoName << *channel->GetChannelID().ToString() << "_" << width << "x" << height;
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
delete image;
|
||||
return;
|
||||
}
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetLogo(string channelID, int width, int height) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
stringstream logoName;
|
||||
logoName << channelID << "_" << width << "x" << height;
|
||||
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
tChannelID chanID = tChannelID::FromString(channelID.c_str());
|
||||
const cChannel *channel = Channels.GetByChannelID(chanID);
|
||||
if (!channel)
|
||||
return NULL;
|
||||
bool success = LoadLogo(channel);
|
||||
if (success) {
|
||||
if (config.limitLogoCache && (channelLogoCache.size() >= config.numLogosMax)) {
|
||||
//logo cache is full, don't cache anymore
|
||||
if (tempStaticLogo) {
|
||||
delete tempStaticLogo;
|
||||
tempStaticLogo = NULL;
|
||||
}
|
||||
tempStaticLogo = CreateImage(width, height);
|
||||
return tempStaticLogo;
|
||||
} else {
|
||||
//add requested logo to cache
|
||||
cImage *image = CreateImage(width, height);
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetSeparatorLogo(string name, int width, int height) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
|
||||
stringstream logoName;
|
||||
logoName << name << "_" << width << "x" << height;
|
||||
|
||||
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
|
||||
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadSeparatorLogo(name);
|
||||
if (success) {
|
||||
//add requested logo to cache
|
||||
cImage *image = CreateImage(width, height);
|
||||
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
|
||||
hit = channelLogoCache.find(logoName.str());
|
||||
if (hit != channelLogoCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cImageCache::LogoExists(string channelID) {
|
||||
tChannelID chanID = tChannelID::FromString(channelID.c_str());
|
||||
const cChannel *channel = Channels.GetByChannelID(chanID);
|
||||
if (!channel)
|
||||
return false;
|
||||
string logoPath = *cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
string logoLower = StrToLowerCase(channel->Name());
|
||||
string logoExt = *config.logoExtension;
|
||||
bool logoExists = FileExists(logoPath, logoLower, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
logoExists = FileExists(logoPath, channelID, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::SeparatorLogoExists(string name) {
|
||||
string separatorPath = *cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
|
||||
string nameLower = StrToLowerCase(name.c_str());
|
||||
string logoExt = *config.logoExtension;
|
||||
bool logoExists = FileExists(separatorPath, nameLower, logoExt);
|
||||
if (logoExists) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return;
|
||||
bool success = LoadIcon(type, name);
|
||||
if (!success)
|
||||
return;
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
cImage *image = CreateImage(width, height, true);
|
||||
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetIcon(eImageType type, string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return NULL;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
map<string, cImage*>::iterator hit = iconCache.find(iconName.str());
|
||||
if (hit != iconCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadIcon(type, name);
|
||||
if (!success)
|
||||
return NULL;
|
||||
cImage *image = CreateImage(width, height, true);
|
||||
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
hit = iconCache.find(iconName.str());
|
||||
if (hit != iconCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string cImageCache::GetIconName(string label) {
|
||||
//check for standard menu entries
|
||||
for (int i=0; i<16; i++) {
|
||||
string s = trVDR(items[i].c_str());
|
||||
if (s == label) {
|
||||
return *cString::sprintf("standardicons/%s", items[i].c_str());
|
||||
}
|
||||
}
|
||||
//check for special main menu entries "stop recording", "stop replay"
|
||||
string stopRecording = skipspace(trVDR(" Stop recording "));
|
||||
string stopReplay = skipspace(trVDR(" Stop replaying"));
|
||||
try {
|
||||
if (label.substr(0, stopRecording.size()) == stopRecording) {
|
||||
return "standardicons/StopRecording";
|
||||
}
|
||||
if (label.substr(0, stopReplay.size()) == stopReplay) {
|
||||
return "standardicons/StopReplay";
|
||||
}
|
||||
} catch (...) {}
|
||||
//check for Plugins
|
||||
for (int i = 0; ; i++) {
|
||||
cPlugin *p = cPluginManager::GetPlugin(i);
|
||||
if (p) {
|
||||
const char *mainMenuEntry = p->MainMenuEntry();
|
||||
if (mainMenuEntry) {
|
||||
string plugMainEntry = mainMenuEntry;
|
||||
try {
|
||||
if (label.substr(0, plugMainEntry.size()) == plugMainEntry) {
|
||||
return *cString::sprintf("pluginicons/%s", p->Name());
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return *cString::sprintf("customicons/%s", label.c_str());
|
||||
}
|
||||
|
||||
void cImageCache::CacheSkinpart(string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return;
|
||||
bool success = LoadSkinpart(name);
|
||||
if (!success)
|
||||
return;
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
cImage *image = CreateImage(width, height, false);
|
||||
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
}
|
||||
|
||||
cImage *cImageCache::GetSkinpart(string name, int width, int height) {
|
||||
if (width < 1 || width > 1920 || height < 1 || height > 1080)
|
||||
return NULL;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
stringstream iconName;
|
||||
iconName << name << "_" << width << "x" << height;
|
||||
map<string, cImage*>::iterator hit = skinPartsCache.find(iconName.str());
|
||||
if (hit != skinPartsCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
} else {
|
||||
bool success = LoadSkinpart(name);
|
||||
if (!success)
|
||||
return NULL;
|
||||
cImage *image = CreateImage(width, height, false);
|
||||
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
|
||||
hit = skinPartsCache.find(iconName.str());
|
||||
if (hit != skinPartsCache.end()) {
|
||||
return (cImage*)hit->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadIcon(eImageType type, string name) {
|
||||
bool success = false;
|
||||
cString subdir("");
|
||||
if (type == itMenuIcon)
|
||||
subdir = "menuicons";
|
||||
else if (type == itIcon)
|
||||
subdir = "icons";
|
||||
cString iconPath = cString::sprintf("%s%s/graphics/%s/", *config.skinPath, Setup.OSDTheme, *subdir);
|
||||
success = LoadImage(name, *iconPath, "png");
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadLogo(const cChannel *channel) {
|
||||
if (!channel)
|
||||
return false;
|
||||
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
|
||||
string logoLower = StrToLowerCase(channel->Name());
|
||||
bool success = false;
|
||||
success = LoadImage(channelID.c_str(), *logoPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
success = LoadImage(logoLower.c_str(), *logoPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadSeparatorLogo(string name) {
|
||||
cString separatorPath = cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
|
||||
string nameLower = StrToLowerCase(name.c_str());
|
||||
bool success = false;
|
||||
success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
|
||||
if (success)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cImageCache::LoadSkinpart(string name) {
|
||||
bool success = false;
|
||||
cString iconPath = cString::sprintf("%s%s/graphics/skinparts/", *config.skinPath, Setup.OSDTheme);
|
||||
success = LoadImage(name, *iconPath, "png");
|
||||
if (success) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageCache::Clear(void) {
|
||||
for(map<string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
iconCache.clear();
|
||||
|
||||
for(map<string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
channelLogoCache.clear();
|
||||
|
||||
for(map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
|
||||
cImage *img = (cImage*)it->second;
|
||||
delete img;
|
||||
}
|
||||
skinPartsCache.clear();
|
||||
}
|
||||
|
||||
void cImageCache::Debug(bool full) {
|
||||
int sizeIconCache = 0;
|
||||
int numIcons = 0;
|
||||
GetIconCacheSize(numIcons, sizeIconCache);
|
||||
dsyslog("skindesigner: cached %d icons - size %d byte", numIcons, sizeIconCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached icon %s", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int sizeLogoCache = 0;
|
||||
int numLogos = 0;
|
||||
GetLogoCacheSize(numLogos, sizeLogoCache);
|
||||
dsyslog("skindesigner: cached %d logos - size %d byte", numLogos, sizeLogoCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached logo %s", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int sizeSkinpartCache = 0;
|
||||
int numSkinparts = 0;
|
||||
GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
|
||||
dsyslog("skindesigner: cached %d skinparts - size %d byte", numSkinparts, sizeSkinpartCache);
|
||||
if (full) {
|
||||
for(std::map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
|
||||
string name = it->first;
|
||||
dsyslog("skindesigner: cached skinpart %s", name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetIconCacheSize(int &num, int &size) {
|
||||
num = iconCache.size();
|
||||
for (map<string, cImage*>::iterator icon = iconCache.begin(); icon != iconCache.end(); icon++) {
|
||||
cImage* img = icon->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetLogoCacheSize(int &num, int &size) {
|
||||
num = channelLogoCache.size();
|
||||
for (map<string, cImage*>::iterator logo = channelLogoCache.begin(); logo != channelLogoCache.end(); logo++) {
|
||||
cImage* img = logo->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
||||
|
||||
void cImageCache::GetSkinpartsCacheSize(int &num, int &size) {
|
||||
num = skinPartsCache.size();
|
||||
for (map<string, cImage*>::iterator skinpart = skinPartsCache.begin(); skinpart != skinPartsCache.end(); skinpart++) {
|
||||
cImage* img = skinpart->second;
|
||||
size += img->Width() * img->Height() * sizeof(tColor);
|
||||
}
|
||||
}
|
53
libcore/imagecache.h
Normal file
53
libcore/imagecache.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef __NOPACITY_IMAGECACHE_H
|
||||
#define __NOPACITY_IMAGECACHE_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/skins.h>
|
||||
#include <Magick++.h>
|
||||
#include <vector>
|
||||
#include "imagemagickwrapper.h"
|
||||
#include "../libtemplate/templatefunction.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageCache : public cImageMagickWrapper {
|
||||
public:
|
||||
cImageCache();
|
||||
~cImageCache();
|
||||
void Lock(void) { mutex.Lock(); }
|
||||
void Unlock(void) { mutex.Unlock(); }
|
||||
//channel logos
|
||||
void CacheLogo(int width, int height);
|
||||
cImage *GetLogo(string channelID, int width, int height);
|
||||
bool LogoExists(string channelID);
|
||||
cImage *GetSeparatorLogo(string name, int width, int height);
|
||||
bool SeparatorLogoExists(string name);
|
||||
//icons
|
||||
void CacheIcon(eImageType type, string path, int width, int height);
|
||||
cImage *GetIcon(eImageType type, string name, int width, int height);
|
||||
string GetIconName(string label);
|
||||
//skinparts
|
||||
void CacheSkinpart(string path, int width, int height);
|
||||
cImage *GetSkinpart(string name, int width, int height);
|
||||
//helpers
|
||||
void Clear(void);
|
||||
void Debug(bool full);
|
||||
void GetIconCacheSize(int &num, int &size);
|
||||
void GetLogoCacheSize(int &num, int &size);
|
||||
void GetSkinpartsCacheSize(int &num, int &size);
|
||||
private:
|
||||
static cMutex mutex;
|
||||
static string items[16];
|
||||
cImage *tempStaticLogo;
|
||||
map<string, cImage*> iconCache;
|
||||
map<string, cImage*> channelLogoCache;
|
||||
map<string, cImage*> skinPartsCache;
|
||||
bool LoadIcon(eImageType type, string name);
|
||||
bool LoadLogo(const cChannel *channel);
|
||||
bool LoadSeparatorLogo(string name);
|
||||
bool LoadSkinpart(string name);
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGECACHE_H
|
56
libcore/imageloader.c
Normal file
56
libcore/imageloader.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "../config.h"
|
||||
#include "helpers.h"
|
||||
#include "imageloader.h"
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <dirent.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
cImageLoader::cImageLoader() : cImageMagickWrapper() {
|
||||
}
|
||||
|
||||
cImageLoader::~cImageLoader() {
|
||||
}
|
||||
|
||||
cImage cImageLoader::GetImage() {
|
||||
return CreateImageCopy();
|
||||
}
|
||||
|
||||
bool cImageLoader::LoadImage(const char *path, int width, int height) {
|
||||
if (cImageMagickWrapper::LoadImage(path)) {
|
||||
buffer.sample(Geometry(width, height));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
|
||||
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
|
||||
cString logoExt = config.logoExtension;
|
||||
DIR *folder = NULL;
|
||||
struct dirent *file;
|
||||
folder = opendir(logoPath);
|
||||
if (!folder) {
|
||||
return;
|
||||
}
|
||||
while (file = readdir(folder)) {
|
||||
if (endswith(file->d_name, *logoExt)) {
|
||||
std::stringstream filePath;
|
||||
filePath << *logoPath << file->d_name;
|
||||
Image logo;
|
||||
try {
|
||||
logo.read(filePath.str().c_str());
|
||||
Geometry g = logo.size();
|
||||
int logoWidth = g.width();
|
||||
int logoHeight = g.height();
|
||||
if (logoWidth > 0 && logoHeight > 0) {
|
||||
width = logoWidth;
|
||||
height = logoHeight;
|
||||
return;
|
||||
}
|
||||
} catch( ... ) { }
|
||||
}
|
||||
}
|
||||
}
|
23
libcore/imageloader.h
Normal file
23
libcore/imageloader.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef __NOPACITY_IMAGELOADER_H
|
||||
#define __NOPACITY_IMAGELOADER_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <vdr/osd.h>
|
||||
#include <vdr/skins.h>
|
||||
#include <Magick++.h>
|
||||
#include "imagemagickwrapper.h"
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageLoader : public cImageMagickWrapper {
|
||||
public:
|
||||
cImageLoader();
|
||||
~cImageLoader();
|
||||
cImage GetImage();
|
||||
bool LoadImage(const char *path, int width, int height);
|
||||
void DeterminateChannelLogoSize(int &width, int &height);
|
||||
private:
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGELOADER_H
|
162
libcore/imagemagickwrapper.c
Normal file
162
libcore/imagemagickwrapper.c
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "imagemagickwrapper.h"
|
||||
#include "../config.h"
|
||||
#include "imagescaler.h"
|
||||
|
||||
cImageMagickWrapper::cImageMagickWrapper() {
|
||||
InitializeMagick(NULL);
|
||||
}
|
||||
|
||||
cImageMagickWrapper::~cImageMagickWrapper() {
|
||||
}
|
||||
|
||||
cImage *cImageMagickWrapper::CreateImage(int width, int height, bool preserveAspect) {
|
||||
int w, h;
|
||||
w = buffer.columns();
|
||||
h = buffer.rows();
|
||||
if (width == 0)
|
||||
width = w;
|
||||
if (height == 0)
|
||||
height = h;
|
||||
if (preserveAspect) {
|
||||
unsigned scale_w = 1000 * width / w;
|
||||
unsigned scale_h = 1000 * height / h;
|
||||
if (scale_w > scale_h)
|
||||
width = w * height / h;
|
||||
else
|
||||
height = h * width / w;
|
||||
}
|
||||
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
|
||||
cImage *image = new cImage(cSize(width, height));
|
||||
tColor *imgData = (tColor *)image->Data();
|
||||
if (w != width || h != height) {
|
||||
ImageScaler scaler;
|
||||
scaler.SetImageParameters(imgData, width, width, height, w, h);
|
||||
for (const void *pixels_end = &pixels[w*h]; pixels < pixels_end; ++pixels)
|
||||
scaler.PutSourcePixel(pixels->blue / ((MaxRGB + 1) / 256),
|
||||
pixels->green / ((MaxRGB + 1) / 256),
|
||||
pixels->red / ((MaxRGB + 1) / 256),
|
||||
~((unsigned char)(pixels->opacity / ((MaxRGB + 1) / 256))));
|
||||
return image;
|
||||
}
|
||||
for (const void *pixels_end = &pixels[width*height]; pixels < pixels_end; ++pixels)
|
||||
*imgData++ = ((~int(pixels->opacity / ((MaxRGB + 1) / 256)) << 24) |
|
||||
(int(pixels->green / ((MaxRGB + 1) / 256)) << 8) |
|
||||
(int(pixels->red / ((MaxRGB + 1) / 256)) << 16) |
|
||||
(int(pixels->blue / ((MaxRGB + 1) / 256)) ));
|
||||
return image;
|
||||
}
|
||||
|
||||
cImage cImageMagickWrapper::CreateImageCopy() {
|
||||
int w, h;
|
||||
w = buffer.columns();
|
||||
h = buffer.rows();
|
||||
cImage image (cSize(w, h));
|
||||
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
tColor col = (~int(pixels->opacity * 255 / MaxRGB) << 24)
|
||||
| (int(pixels->green * 255 / MaxRGB) << 8)
|
||||
| (int(pixels->red * 255 / MaxRGB) << 16)
|
||||
| (int(pixels->blue * 255 / MaxRGB) );
|
||||
image.SetPixel(cPoint(ix, iy), col);
|
||||
++pixels;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool cImageMagickWrapper::LoadImage(std::string FileName, std::string Path, std::string Extension) {
|
||||
try {
|
||||
std::stringstream sstrImgFile;
|
||||
sstrImgFile << Path << FileName << "." << Extension;
|
||||
std::string imgFile = sstrImgFile.str();
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: trying to load: %s", imgFile.c_str());
|
||||
buffer.read(imgFile.c_str());
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: %s sucessfully loaded", imgFile.c_str());
|
||||
} catch( Magick::Warning &warning ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Warning: %s", warning.what());
|
||||
return true;
|
||||
} catch( Magick::Error &error ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Error: %s", error.what());
|
||||
return false;
|
||||
} catch(...) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: an unknown Magick error occured during image loading");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cImageMagickWrapper::LoadImage(const char *fullpath) {
|
||||
if ((fullpath == NULL) || (strlen(fullpath) < 5))
|
||||
return false;
|
||||
try {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: trying to load: %s", fullpath);
|
||||
buffer.read(fullpath);
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: %s sucessfully loaded", fullpath);
|
||||
} catch( Magick::Warning &warning ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Warning: %s", warning.what());
|
||||
return true;
|
||||
} catch( Magick::Error &error ) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: Magick Error: %s", error.what());
|
||||
return false;
|
||||
} catch(...) {
|
||||
if (config.debugImageLoading)
|
||||
dsyslog("skindesigner: an unknown Magick error occured during image loading");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Color cImageMagickWrapper::Argb2Color(tColor col) {
|
||||
tIndex alpha = (col & 0xFF000000) >> 24;
|
||||
tIndex red = (col & 0x00FF0000) >> 16;
|
||||
tIndex green = (col & 0x0000FF00) >> 8;
|
||||
tIndex blue = (col & 0x000000FF);
|
||||
Color color(MaxRGB*red/255, MaxRGB*green/255, MaxRGB*blue/255, MaxRGB*(0xFF-alpha)/255);
|
||||
return color;
|
||||
}
|
||||
|
||||
void cImageMagickWrapper::CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor) {
|
||||
Color Back = Argb2Color(back);
|
||||
Color Blend = Argb2Color(blend);
|
||||
int maxw = MaxRGB * wfactor;
|
||||
int maxh = MaxRGB * hfactor;
|
||||
|
||||
Image imgblend(Geometry(width, height), Blend);
|
||||
imgblend.modifyImage();
|
||||
imgblend.type(TrueColorMatteType);
|
||||
PixelPacket *pixels = imgblend.getPixels(0, 0, width, height);
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
PixelPacket *pixel = pixels + y * width + x;
|
||||
int opacity = (maxw / width * x + maxh - maxh / height * y) / 2;
|
||||
pixel->opacity = (opacity <= MaxRGB) ? opacity : MaxRGB;
|
||||
}
|
||||
}
|
||||
imgblend.syncPixels();
|
||||
|
||||
Image imgback(Geometry(width, height), Back);
|
||||
imgback.composite(imgblend, 0, 0, OverCompositeOp);
|
||||
|
||||
buffer = imgback;
|
||||
}
|
||||
|
||||
void cImageMagickWrapper::CreateBackground(tColor back, tColor blend, int width, int height, bool mirror) {
|
||||
CreateGradient(back, blend, width, height, 0.8, 0.8);
|
||||
if (mirror)
|
||||
buffer.flop();
|
||||
}
|
||||
void cImageMagickWrapper::CreateBackgroundReverse(tColor back, tColor blend, int width, int height) {
|
||||
CreateGradient(back, blend, width, height, 1.3, 0.7);
|
||||
}
|
28
libcore/imagemagickwrapper.h
Normal file
28
libcore/imagemagickwrapper.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef __NOPACITY_IMAGEMAGICKWRAPPER_H
|
||||
#define __NOPACITY_IMAGEMAGICKWRAPPER_H
|
||||
|
||||
#define X_DISPLAY_MISSING
|
||||
|
||||
#include <Magick++.h>
|
||||
#include <vdr/osd.h>
|
||||
|
||||
using namespace Magick;
|
||||
|
||||
class cImageMagickWrapper {
|
||||
private:
|
||||
void CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor);
|
||||
public:
|
||||
cImageMagickWrapper();
|
||||
~cImageMagickWrapper();
|
||||
protected:
|
||||
Image buffer;
|
||||
Color Argb2Color(tColor col);
|
||||
cImage *CreateImage(int width, int height, bool preserveAspect = true);
|
||||
cImage CreateImageCopy(void);
|
||||
bool LoadImage(std::string FileName, std::string Path, std::string Extension);
|
||||
bool LoadImage(const char *fullpath);
|
||||
void CreateBackground(tColor back, tColor blend, int width, int height, bool mirror = false);
|
||||
void CreateBackgroundReverse(tColor back, tColor blend, int width, int height);
|
||||
};
|
||||
|
||||
#endif //__NOPACITY_IMAGEMAGICKWRAPPER_H
|
149
libcore/imagescaler.c
Normal file
149
libcore/imagescaler.c
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
#include "imagescaler.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
|
||||
ImageScaler::ImageScaler() :
|
||||
m_memory(NULL),
|
||||
m_hor_filters(NULL),
|
||||
m_ver_filters(NULL),
|
||||
m_buffer(NULL),
|
||||
m_dst_image(NULL),
|
||||
m_dst_stride(0),
|
||||
m_dst_width(0),
|
||||
m_dst_height(0),
|
||||
m_src_width(0),
|
||||
m_src_height(0),
|
||||
m_src_x(0),
|
||||
m_src_y(0),
|
||||
m_dst_x(0),
|
||||
m_dst_y(0) {
|
||||
}
|
||||
|
||||
ImageScaler::~ImageScaler() {
|
||||
if ( m_memory ) free( m_memory );
|
||||
}
|
||||
|
||||
// sin(x)/(x)
|
||||
static float sincf( float x ) {
|
||||
if ( fabsf(x) < 0.05f ) return 1.0f - (1.0f/6.0f)*x*x; // taylor series approximation to avoid 0/0
|
||||
return sin(x)/x;
|
||||
}
|
||||
|
||||
static void CalculateFilters( ImageScaler::Filter *filters, int dst_size, int src_size ) {
|
||||
const float fc = dst_size >= src_size ? 1.0f : ((float) dst_size)/((float) src_size);
|
||||
|
||||
for (int i = 0; i < dst_size; i++) {
|
||||
const int d = 2*dst_size; // sample position denominator
|
||||
const int e = (2*i+1) * src_size - dst_size; // sample position enumerator
|
||||
int offset = e / d; // truncated sample position
|
||||
const float sub_offset = ((float) (e - offset*d)) / ((float) d); // exact sample position is (float) e/d = offset + sub_offset
|
||||
|
||||
// calculate filter coefficients
|
||||
float h[4];
|
||||
for (int j=0; j<4; j++) {
|
||||
const float t = 3.14159265359f * (sub_offset+(1-j));
|
||||
h[j] = sincf( fc * t ) * cosf( 0.25f * t ); // sinc-lowpass and cos-window
|
||||
}
|
||||
|
||||
// ensure that filter does not reach out off image bounds:
|
||||
while ( offset < 1 ) {
|
||||
h[0] += h[1];
|
||||
h[1] = h[2];
|
||||
h[2] = h[3];
|
||||
h[3] = 0.0f;
|
||||
offset++;
|
||||
}
|
||||
|
||||
while ( offset+3 > src_size ) {
|
||||
h[3] += h[2];
|
||||
h[2] = h[1];
|
||||
h[1] = h[0];
|
||||
h[0] = 0.0f;
|
||||
offset--;
|
||||
}
|
||||
|
||||
// coefficients are normalized to sum up to 2048
|
||||
const float norm = 2048.0f / ( h[0] + h[1] + h[2] + h[3] );
|
||||
|
||||
offset--; // offset of fist used pixel
|
||||
|
||||
filters[i].m_offset = offset + 4; // store offset of first unused pixel
|
||||
|
||||
for (int j=0; j<4; j++) {
|
||||
const float t = norm * h[j];
|
||||
filters[i].m_coeff[(offset+j) & 3] = (int) ((t > 0.0f) ? (t+0.5f) : (t-0.5f)); // consider ring buffer index permutations
|
||||
}
|
||||
}
|
||||
|
||||
// set end marker
|
||||
filters[dst_size].m_offset = (unsigned) -1;
|
||||
|
||||
}
|
||||
|
||||
void ImageScaler::SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ) {
|
||||
m_src_x = 0;
|
||||
m_src_y = 0;
|
||||
m_dst_x = 0;
|
||||
m_dst_y = 0;
|
||||
|
||||
m_dst_image = dst_image;
|
||||
m_dst_stride = dst_stride;
|
||||
|
||||
// if image dimensions do not change we can keep the old filter coefficients
|
||||
if ( (src_width == m_src_width) && (src_height == m_src_height) && (dst_width == m_dst_width) && (dst_height == m_dst_height) ) return;
|
||||
|
||||
m_dst_width = dst_width;
|
||||
m_dst_height = dst_height;
|
||||
m_src_width = src_width;
|
||||
m_src_height = src_height;
|
||||
|
||||
if ( m_memory ) free( m_memory );
|
||||
|
||||
const unsigned hor_filters_size = (m_dst_width + 1) * sizeof(Filter); // reserve one extra position for end marker
|
||||
const unsigned ver_filters_size = (m_dst_height + 1) * sizeof(Filter);
|
||||
const unsigned buffer_size = 4 * m_dst_width * sizeof(TmpPixel);
|
||||
|
||||
char *p = (char *) malloc( hor_filters_size + ver_filters_size + buffer_size );
|
||||
|
||||
m_memory = p;
|
||||
|
||||
m_hor_filters = (Filter *) p; p += hor_filters_size;
|
||||
m_ver_filters = (Filter *) p; p += ver_filters_size;
|
||||
m_buffer = (TmpPixel *) p;
|
||||
|
||||
CalculateFilters( m_hor_filters, m_dst_width , m_src_width );
|
||||
CalculateFilters( m_ver_filters, m_dst_height, m_src_height );
|
||||
}
|
||||
|
||||
// shift range to 0..255 and clamp overflows
|
||||
static unsigned shift_clamp( int x ) {
|
||||
x = ( x + (1<<21) ) >> 22;
|
||||
if ( x < 0 ) return 0;
|
||||
if ( x > 255 ) return 255;
|
||||
return x;
|
||||
}
|
||||
|
||||
void ImageScaler::NextSourceLine() {
|
||||
m_dst_x = 0;
|
||||
m_src_x = 0;
|
||||
m_src_y++;
|
||||
|
||||
while ( m_ver_filters[m_dst_y].m_offset == m_src_y ) {
|
||||
const int h0 = m_ver_filters[m_dst_y].m_coeff[0];
|
||||
const int h1 = m_ver_filters[m_dst_y].m_coeff[1];
|
||||
const int h2 = m_ver_filters[m_dst_y].m_coeff[2];
|
||||
const int h3 = m_ver_filters[m_dst_y].m_coeff[3];
|
||||
const TmpPixel *src = m_buffer;
|
||||
unsigned *dst = m_dst_image + m_dst_stride * m_dst_y;
|
||||
|
||||
for (unsigned i=0; i<m_dst_width; i++) {
|
||||
const ImageScaler::TmpPixel t( src[0]*h0 + src[1]*h1 + src[2]*h2 + src[3]*h3 );
|
||||
src += 4;
|
||||
dst[i] = shift_clamp(t[0]) | (shift_clamp(t[1])<<8) | (shift_clamp(t[2])<<16) | (shift_clamp(t[3])<<24);
|
||||
}
|
||||
|
||||
m_dst_y++;
|
||||
}
|
||||
}
|
97
libcore/imagescaler.h
Normal file
97
libcore/imagescaler.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef _ImageScaler_h
|
||||
#define _ImageScaler_h
|
||||
|
||||
/*!
|
||||
* this class scales images consisting of 4 components (RGBA)
|
||||
* to an arbitrary size using a 4-tap filter
|
||||
*/
|
||||
class ImageScaler {
|
||||
public:
|
||||
|
||||
struct Filter {
|
||||
unsigned m_offset;
|
||||
short m_coeff[4];
|
||||
};
|
||||
|
||||
ImageScaler();
|
||||
~ImageScaler();
|
||||
|
||||
//! set destination image and source image size
|
||||
void SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height );
|
||||
|
||||
/*! process one pixel of source image; destination image is written while input is processed
|
||||
* SetImageParameters() must be called first
|
||||
*/
|
||||
void PutSourcePixel( unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3 ) {
|
||||
m_hbuf[ (m_src_x++) & 3 ].Set( c0, c1, c2, c3 );
|
||||
|
||||
TmpPixel *bp = m_buffer + 4 * m_dst_x + (m_src_y & 3);
|
||||
const Filter *fh;
|
||||
|
||||
while ( (fh=m_hor_filters+m_dst_x)->m_offset == m_src_x ) {
|
||||
*bp = m_hbuf[0]*fh->m_coeff[0] + m_hbuf[1]*fh->m_coeff[1] + m_hbuf[2]*fh->m_coeff[2] + m_hbuf[3]*fh->m_coeff[3];
|
||||
m_dst_x++;
|
||||
bp += 4;
|
||||
}
|
||||
|
||||
if ( m_src_x == m_src_width ) NextSourceLine();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! temporary image pixel class - a 4-element integer vector
|
||||
class TmpPixel {
|
||||
public:
|
||||
TmpPixel() {
|
||||
}
|
||||
|
||||
TmpPixel( int c0, int c1, int c2, int c3 ) {
|
||||
Set(c0,c1,c2,c3);
|
||||
}
|
||||
|
||||
void Set( int c0, int c1, int c2, int c3 ) {
|
||||
m_comp[0] = c0;
|
||||
m_comp[1] = c1;
|
||||
m_comp[2] = c2;
|
||||
m_comp[3] = c3;
|
||||
}
|
||||
|
||||
TmpPixel operator*( int s ) const {
|
||||
return TmpPixel( m_comp[0]*s, m_comp[1]*s, m_comp[2]*s, m_comp[3]*s );
|
||||
}
|
||||
|
||||
TmpPixel operator+( const TmpPixel &x ) const {
|
||||
return TmpPixel( m_comp[0] + x[0], m_comp[1] + x[1], m_comp[2] + x[2], m_comp[3] + x[3] );
|
||||
}
|
||||
|
||||
// return component i=[0..3] - No range check!
|
||||
int operator[](unsigned i) const {
|
||||
return m_comp[i];
|
||||
}
|
||||
|
||||
private:
|
||||
int m_comp[4];
|
||||
};
|
||||
|
||||
//! this is called whenever one input line is processed completely
|
||||
void NextSourceLine();
|
||||
|
||||
TmpPixel m_hbuf[4]; //! ring buffer for 4 input pixels
|
||||
char *m_memory; //! buffer container
|
||||
Filter *m_hor_filters; //! buffer for horizontal filters (one for each output image column)
|
||||
Filter *m_ver_filters; //! buffer for vertical filters (one for each output image row)
|
||||
TmpPixel *m_buffer; //! buffer contains 4 horizontally filtered input lines, multiplexed
|
||||
unsigned *m_dst_image; //! pointer to destination image
|
||||
unsigned m_dst_stride; //! destination image stride
|
||||
unsigned m_dst_width; //! destination image width
|
||||
unsigned m_dst_height; //! destination image height
|
||||
unsigned m_src_width; //! source image width
|
||||
unsigned m_src_height; //! source image height
|
||||
unsigned m_src_x; //! x position of next source image pixel
|
||||
unsigned m_src_y; //! y position of source image line currently beeing processed
|
||||
unsigned m_dst_x; //! x position of next destination image pixel
|
||||
unsigned m_dst_y; //! x position of next destination image line
|
||||
};
|
||||
|
||||
#endif // _ImageScaler_h
|
||||
|
477
libcore/pixmapcontainer.c
Normal file
477
libcore/pixmapcontainer.c
Normal file
@@ -0,0 +1,477 @@
|
||||
#define __STL_CONFIG_H
|
||||
#include "pixmapcontainer.h"
|
||||
#include "../config.h"
|
||||
|
||||
cMutex cPixmapContainer::mutex;
|
||||
cOsd *cPixmapContainer::osd = NULL;
|
||||
eFlushState cPixmapContainer::flushState = fsOpen;
|
||||
|
||||
cPixmapContainer::cPixmapContainer(int numPixmaps) {
|
||||
this->numPixmaps = numPixmaps;
|
||||
pixContainerInit = true;
|
||||
mutex.Lock();
|
||||
pixmaps = new cPixmap*[numPixmaps];
|
||||
pixmapsTransparency = new int[numPixmaps];
|
||||
for(int i=0; i < numPixmaps; i++) {
|
||||
pixmaps[i] = NULL;
|
||||
pixmapsTransparency[i] = 0;
|
||||
}
|
||||
mutex.Unlock();
|
||||
checkRunning = false;
|
||||
fadeTime = 0;
|
||||
deleteOsdOnExit = false;
|
||||
}
|
||||
|
||||
cPixmapContainer::~cPixmapContainer(void) {
|
||||
for (int i=0; i < numPixmaps; i++) {
|
||||
mutex.Lock();
|
||||
if (pixmaps[i] && osd) {
|
||||
osd->DestroyPixmap(pixmaps[i]);
|
||||
pixmaps[i] = NULL;
|
||||
}
|
||||
mutex.Unlock();
|
||||
}
|
||||
delete[] pixmaps;
|
||||
delete[] pixmapsTransparency;
|
||||
if (deleteOsdOnExit && osd) {
|
||||
mutex.Lock();
|
||||
delete osd;
|
||||
osd = NULL;
|
||||
mutex.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool cPixmapContainer::CreateOsd(int Left, int Top, int Width, int Height) {
|
||||
if (osd) {
|
||||
return true;
|
||||
}
|
||||
cOsd *newOsd = cOsdProvider::NewOsd(Left, Top);
|
||||
if (newOsd) {
|
||||
tArea Area = { 0, 0, Width, Height, 32 };
|
||||
if (newOsd->SetAreas(&Area, 1) == oeOk) {
|
||||
osd = newOsd;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::LockFlush(void) {
|
||||
flushState = fsLock;
|
||||
}
|
||||
|
||||
void cPixmapContainer::OpenFlush(void) {
|
||||
flushState = fsOpen;
|
||||
}
|
||||
|
||||
bool cPixmapContainer::PixmapExists(int num) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (pixmaps[num])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::DoFlush(void) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!osd || (checkRunning && !Running()))
|
||||
return;
|
||||
if (flushState == fsOpen) {
|
||||
osd->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!osd || (checkRunning && !Running()))
|
||||
return;
|
||||
pixmaps[num] = osd->CreatePixmap(Layer, ViewPort, DrawPort);
|
||||
pixmaps[num]->Fill(clrTransparent);
|
||||
if (pixContainerInit && fadeTime) {
|
||||
pixmaps[num]->SetAlpha(0);
|
||||
} else if (pixmapsTransparency[num] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[num])*255/100;
|
||||
pixmaps[num]->SetAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
bool cPixmapContainer::DestroyPixmap(int num) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (pixmaps[num] && osd) {
|
||||
osd->DestroyPixmap(pixmaps[num]);
|
||||
pixmaps[num] = NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
fontManager->Lock();
|
||||
cFont *font = fontManager->Font(fontName, fontSize);
|
||||
if (font)
|
||||
pixmaps[num]->DrawText(Point, s, ColorFg, ColorBg, font);
|
||||
fontManager->Unlock();
|
||||
}
|
||||
|
||||
|
||||
void cPixmapContainer::DrawRectangle(int num, const cRect &Rect, tColor Color) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawRectangle(Rect, Color);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawEllipse(Rect, Color, Quadrants);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawImage(int num, const cPoint &Point, const cImage &Image) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawImage(Point, Image);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->DrawBitmap(Point, Bitmap, ColorFg, ColorBg, Overlay);
|
||||
}
|
||||
|
||||
void cPixmapContainer::Fill(int num, tColor Color) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->Fill(Color);
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetAlpha(int num, int Alpha) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetAlpha(Alpha);
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetTransparency(int num, int Transparency) {
|
||||
if (Transparency < 0 && Transparency > 100)
|
||||
return;
|
||||
pixmapsTransparency[num] = Transparency;
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetLayer(int num, int Layer) {
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetLayer(Layer);
|
||||
}
|
||||
|
||||
int cPixmapContainer::Width(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int width = pixmaps[num]->ViewPort().Width();
|
||||
return width;
|
||||
}
|
||||
|
||||
int cPixmapContainer::Height(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int height = pixmaps[num]->ViewPort().Height();
|
||||
return height;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportWidth(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int width = pixmaps[num]->DrawPort().Width();
|
||||
return width;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportHeight(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int height = pixmaps[num]->DrawPort().Height();
|
||||
return height;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportX(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int x = pixmaps[num]->DrawPort().X();
|
||||
return x;
|
||||
}
|
||||
|
||||
int cPixmapContainer::DrawportY(int num) {
|
||||
if (checkRunning && !Running())
|
||||
return 0;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return 0;
|
||||
int y = pixmaps[num]->DrawPort().Y();
|
||||
return y;
|
||||
}
|
||||
|
||||
void cPixmapContainer::SetDrawPortPoint(int num, const cPoint &Point) {
|
||||
if (checkRunning && !Running())
|
||||
return;
|
||||
cMutexLock MutexLock(&mutex);
|
||||
if (!pixmaps[num])
|
||||
return;
|
||||
pixmaps[num]->SetDrawPortPoint(Point);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* HELPERS -- do not access the pixmaps array directly, use wrapper functions
|
||||
* to ensure that a proper lock is set before accessing pixmaps
|
||||
****************************************************************************/
|
||||
|
||||
void cPixmapContainer::FadeIn(void) {
|
||||
if (!fadeTime)
|
||||
return;
|
||||
uint64_t Start = cTimeMs::Now();
|
||||
int FadeFrameTime = fadeTime / 10;
|
||||
while (Running()) {
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
double t = min(double(Now - Start) / fadeTime, 1.0);
|
||||
int Alpha = t * ALPHA_OPAQUE;
|
||||
for (int i = 0; i < numPixmaps; i++) {
|
||||
if (!PixmapExists(i))
|
||||
continue;
|
||||
if (pixmapsTransparency[i] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
||||
SetAlpha(i, alpha);
|
||||
} else {
|
||||
SetAlpha(i, Alpha);
|
||||
}
|
||||
}
|
||||
DoFlush();
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
if (Running() && (Delta < FadeFrameTime))
|
||||
cCondWait::SleepMs(FadeFrameTime - Delta);
|
||||
if ((int)(Now - Start) > fadeTime)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::FadeOut(void) {
|
||||
if (!fadeTime)
|
||||
return;
|
||||
uint64_t Start = cTimeMs::Now();
|
||||
int FadeFrameTime = fadeTime / 10;
|
||||
while (true) {
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
double t = min(double(Now - Start) / fadeTime, 1.0);
|
||||
int Alpha = (1 - t) * ALPHA_OPAQUE;
|
||||
for (int i = 0; i < numPixmaps; i++) {
|
||||
if (!PixmapExists(i))
|
||||
continue;
|
||||
if (pixmapsTransparency[i] > 0) {
|
||||
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
|
||||
SetAlpha(i, alpha);
|
||||
} else {
|
||||
SetAlpha(i, Alpha);
|
||||
}
|
||||
}
|
||||
DoFlush();
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
if (Running() && (Delta < FadeFrameTime))
|
||||
cCondWait::SleepMs(FadeFrameTime - Delta);
|
||||
if ((int)(Now - Start) > fadeTime)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* scrollSpeed: 1 slow
|
||||
* 2 medium
|
||||
* 3 fast
|
||||
******************************************/
|
||||
void cPixmapContainer::ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode) {
|
||||
bool carriageReturn = (scrollMode == 1) ? true : false;
|
||||
|
||||
int scrollDelta = 1;
|
||||
int drawPortX;
|
||||
|
||||
int FrameTime = 0;
|
||||
if (scrollSpeed == 1)
|
||||
FrameTime = 50;
|
||||
else if (scrollSpeed == 2)
|
||||
FrameTime = 30;
|
||||
else
|
||||
FrameTime = 15;
|
||||
if (!Running())
|
||||
return;
|
||||
int maxX = DrawportWidth(num) - Width(num);
|
||||
bool doSleep = false;
|
||||
while (Running()) {
|
||||
if (doSleep) {
|
||||
DoSleep(scrollDelay);
|
||||
doSleep = false;
|
||||
}
|
||||
if (!Running())
|
||||
return;
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
drawPortX = DrawportX(num);
|
||||
drawPortX -= scrollDelta;
|
||||
|
||||
if (abs(drawPortX) > maxX) {
|
||||
DoSleep(scrollDelay);
|
||||
if (carriageReturn)
|
||||
drawPortX = 0;
|
||||
else {
|
||||
scrollDelta *= -1;
|
||||
drawPortX -= scrollDelta;
|
||||
}
|
||||
doSleep = true;
|
||||
}
|
||||
if (!carriageReturn && (drawPortX == 0)) {
|
||||
scrollDelta *= -1;
|
||||
doSleep = true;
|
||||
}
|
||||
SetDrawPortPoint(num, cPoint(drawPortX, 0));
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
DoFlush();
|
||||
if (Running() && (Delta < FrameTime))
|
||||
cCondWait::SleepMs(FrameTime - Delta);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* scrollSpeed: 1 slow
|
||||
* 2 medium
|
||||
* 3 fast
|
||||
******************************************/
|
||||
void cPixmapContainer::ScrollVertical(int num, int scrollDelay, int scrollSpeed) {
|
||||
if (!scrollSpeed)
|
||||
return;
|
||||
DoSleep(scrollDelay);
|
||||
int drawPortY;
|
||||
int FrameTime = 0;
|
||||
if (scrollSpeed == 1)
|
||||
FrameTime = 50;
|
||||
else if (scrollSpeed == 2)
|
||||
FrameTime = 30;
|
||||
else
|
||||
FrameTime = 15;
|
||||
int maxY = DrawportHeight(num) - Height(num);
|
||||
bool doSleep = false;
|
||||
while (Running()) {
|
||||
if (doSleep) {
|
||||
doSleep = false;
|
||||
DoSleep(scrollDelay);
|
||||
}
|
||||
uint64_t Now = cTimeMs::Now();
|
||||
drawPortY = DrawportY(num);
|
||||
drawPortY -= 1;
|
||||
if (abs(drawPortY) > maxY) {
|
||||
doSleep = true;
|
||||
DoSleep(scrollDelay);
|
||||
drawPortY = 0;
|
||||
}
|
||||
SetDrawPortPoint(num, cPoint(0, drawPortY));
|
||||
if (doSleep) {
|
||||
DoSleep(scrollDelay);
|
||||
}
|
||||
int Delta = cTimeMs::Now() - Now;
|
||||
DoFlush();
|
||||
if (Running() && (Delta < FrameTime))
|
||||
cCondWait::SleepMs(FrameTime - Delta);
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::CancelSave(void) {
|
||||
Cancel(-1);
|
||||
while (Active())
|
||||
cCondWait::SleepMs(10);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DoSleep(int duration) {
|
||||
int sleepSlice = 10;
|
||||
for (int i = 0; Running() && (i*sleepSlice < duration); i++)
|
||||
cCondWait::SleepMs(sleepSlice);
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop) {
|
||||
int height = Height(num);
|
||||
int numSteps = 16;
|
||||
int alphaStep = 0x0F;
|
||||
int alpha = 0x00;
|
||||
int step, begin, end;
|
||||
if (fromTop) {
|
||||
step = 1;
|
||||
begin = 0;
|
||||
end = numSteps;
|
||||
} else {
|
||||
step = -1;
|
||||
begin = height;
|
||||
end = height - numSteps;
|
||||
}
|
||||
tColor clr;
|
||||
bool cont = true;
|
||||
for (int i = begin; cont; i = i + step) {
|
||||
clr = AlphaBlend(color, colorBlending, alpha);
|
||||
DrawRectangle(num, cRect(xStart,i,width,1), clr);
|
||||
alpha += alphaStep;
|
||||
if (i == end)
|
||||
cont = false;
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawRoundedCorners(int num, int radius, int x, int y, int width, int height) {
|
||||
if (radius > 2) {
|
||||
DrawEllipse(num, cRect(x, y, radius, radius), clrTransparent, -2);
|
||||
DrawEllipse(num, cRect(x + width - radius, y , radius, radius), clrTransparent, -1);
|
||||
DrawEllipse(num, cRect(x, y + height - radius, radius, radius), clrTransparent, -3);
|
||||
DrawEllipse(num, cRect(x + width - radius, y + height - radius, radius, radius), clrTransparent, -4);
|
||||
}
|
||||
}
|
||||
|
||||
void cPixmapContainer::DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height) {
|
||||
if (radius < 3)
|
||||
return;
|
||||
DrawEllipse(num, cRect(0,0,radius,radius), borderColor, -2);
|
||||
DrawEllipse(num, cRect(-1,-1,radius,radius), clrTransparent, -2);
|
||||
|
||||
DrawEllipse(num, cRect(width-radius,0,radius,radius), borderColor, -1);
|
||||
DrawEllipse(num, cRect(width-radius+1,-1,radius,radius), clrTransparent, -1);
|
||||
|
||||
DrawEllipse(num, cRect(0,height-radius,radius,radius), borderColor, -3);
|
||||
DrawEllipse(num, cRect(-1,height-radius+1,radius,radius), clrTransparent, -3);
|
||||
|
||||
DrawEllipse(num, cRect(width-radius,height-radius,radius,radius), borderColor, -4);
|
||||
DrawEllipse(num, cRect(width-radius+1,height-radius+1,radius,radius), clrTransparent, -4);
|
||||
}
|
73
libcore/pixmapcontainer.h
Normal file
73
libcore/pixmapcontainer.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef __PIXMAP_CONTAINER_H
|
||||
#define __PIXMAP_CONTAINER_H
|
||||
|
||||
#include <string>
|
||||
#include <vdr/plugin.h>
|
||||
#include "fontmanager.h"
|
||||
|
||||
enum eFlushState {
|
||||
fsOpen,
|
||||
fsLock,
|
||||
fsCount,
|
||||
};
|
||||
|
||||
class cPixmapContainer : public cThread {
|
||||
private:
|
||||
static cMutex mutex;
|
||||
static cOsd *osd;
|
||||
static eFlushState flushState;
|
||||
bool pixContainerInit;
|
||||
int numPixmaps;
|
||||
cPixmap **pixmaps;
|
||||
int *pixmapsTransparency;
|
||||
bool checkRunning;
|
||||
int fadeTime;
|
||||
bool deleteOsdOnExit;
|
||||
protected:
|
||||
void SetInitFinished(void) { pixContainerInit = false; };
|
||||
bool CreateOsd(int Left, int Top, int Width, int Height);
|
||||
void DeleteOsdOnExit(void) { deleteOsdOnExit = true; };
|
||||
void LockFlush(void);
|
||||
void OpenFlush(void);
|
||||
//Wrappers for access to pixmaps
|
||||
bool PixmapExists(int num);
|
||||
int NumPixmaps(void) { return numPixmaps; };
|
||||
void CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
|
||||
bool DestroyPixmap(int num);
|
||||
void DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize);
|
||||
void DrawRectangle(int num, const cRect &Rect, tColor Color);
|
||||
void DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants = 0);
|
||||
void DrawImage(int num, const cPoint &Point, const cImage &Image);
|
||||
void DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false);
|
||||
void Fill(int num, tColor Color);
|
||||
void SetAlpha(int num, int Alpha);
|
||||
void SetTransparency(int num, int Transparency);
|
||||
void SetLayer(int num, int Layer);
|
||||
int Width(int num);
|
||||
int Height(int num);
|
||||
int DrawportWidth(int num);
|
||||
int DrawportHeight(int num);
|
||||
int DrawportX(int num);
|
||||
int DrawportY(int num);
|
||||
void SetDrawPortPoint(int num, const cPoint &Point);
|
||||
void SetCheckRunning(void) { checkRunning = true; };
|
||||
void UnsetCheckRunning(void) { checkRunning = false; };
|
||||
//HELPERS -- do not access the pixmaps array directly, use wrapper functions
|
||||
void SetFadeTime(int fade) { fadeTime = fade; };
|
||||
void FadeIn(void);
|
||||
void FadeOut(void);
|
||||
void ScrollVertical(int num, int scrollDelay, int scrollSpeed);
|
||||
void ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode);
|
||||
void CancelSave(void);
|
||||
void DoSleep(int duration);
|
||||
void DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop);
|
||||
void DrawRoundedCorners(int num, int radius, int x, int y, int width, int height);
|
||||
void DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height);
|
||||
public:
|
||||
cPixmapContainer(int numPixmaps);
|
||||
virtual ~cPixmapContainer(void);
|
||||
void DoFlush(void);
|
||||
virtual void Action(void) {};
|
||||
};
|
||||
|
||||
#endif //__PIXMAP_CONTAINER_H
|
84
libcore/timers.c
Normal file
84
libcore/timers.c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "timers.h"
|
||||
#include "../services/epgsearch.h"
|
||||
#include "../services/remotetimers.h"
|
||||
|
||||
static int CompareTimers(const void *a, const void *b) {
|
||||
return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
|
||||
}
|
||||
|
||||
cGlobalSortedTimers::cGlobalSortedTimers(bool forceRefresh) : cVector<const cTimer *>(Timers.Count()) {
|
||||
static bool initial = true;
|
||||
static cRemoteTimerRefresh *remoteTimerRefresh = NULL;
|
||||
|
||||
if (forceRefresh)
|
||||
initial = true;
|
||||
//check if remotetimers plugin is available
|
||||
static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
|
||||
|
||||
cSchedulesLock SchedulesLock;
|
||||
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
|
||||
|
||||
if (pRemoteTimers && initial) {
|
||||
cString errorMsg;
|
||||
pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
|
||||
initial = false;
|
||||
}
|
||||
|
||||
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
|
||||
Append(Timer);
|
||||
|
||||
//if remotetimers plugin is available, take timers also from him
|
||||
if (pRemoteTimers) {
|
||||
cTimer* remoteTimer = NULL;
|
||||
while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
|
||||
remoteTimer->SetEventFromSchedule(Schedules); // make sure the event is current
|
||||
Append(remoteTimer);
|
||||
}
|
||||
}
|
||||
|
||||
Sort(CompareTimers);
|
||||
|
||||
if (pRemoteTimers && (remoteTimerRefresh == NULL))
|
||||
remoteTimerRefresh = new cRemoteTimerRefresh();
|
||||
}
|
||||
|
||||
int cGlobalSortedTimers::NumTimerConfilicts(void) {
|
||||
int numConflicts = 0;
|
||||
cPlugin *p = cPluginManager::GetPlugin("epgsearch");
|
||||
if (p) {
|
||||
Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
|
||||
if (serviceData) {
|
||||
serviceData->nextConflict = 0;
|
||||
serviceData->relevantConflicts = 0;
|
||||
serviceData->totalConflicts = 0;
|
||||
p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
|
||||
if (serviceData->relevantConflicts > 0) {
|
||||
numConflicts = serviceData->relevantConflicts;
|
||||
}
|
||||
delete serviceData;
|
||||
}
|
||||
}
|
||||
return numConflicts;
|
||||
}
|
||||
|
||||
cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
|
||||
Start();
|
||||
}
|
||||
|
||||
cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
|
||||
Cancel(-1);
|
||||
while (Active())
|
||||
cCondWait::SleepMs(10);
|
||||
}
|
||||
|
||||
void cRemoteTimerRefresh::Action(void) {
|
||||
#define REFESH_INTERVALL_MS 30000
|
||||
while (Running()) {
|
||||
cCondWait::SleepMs(REFESH_INTERVALL_MS);
|
||||
if (!cOsd::IsOpen()) {//make sure that no timer is currently being edited
|
||||
cGlobalSortedTimers(true);
|
||||
Timers.SetModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
libcore/timers.h
Normal file
20
libcore/timers.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __NOPACITY_TIMERS_H
|
||||
#define __NOPACITY_TIMERS_H
|
||||
|
||||
#include <vdr/timers.h>
|
||||
#include <vdr/plugin.h>
|
||||
|
||||
class cGlobalSortedTimers : public cVector<const cTimer *> {
|
||||
public:
|
||||
cGlobalSortedTimers(bool forceRefresh = false);
|
||||
int NumTimerConfilicts(void);
|
||||
};
|
||||
|
||||
class cRemoteTimerRefresh: public cThread {
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
public:
|
||||
cRemoteTimerRefresh(void);
|
||||
virtual ~cRemoteTimerRefresh(void);
|
||||
};
|
||||
#endif //__NOPACITY_TIMERS_H
|
Reference in New Issue
Block a user