mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 17:58:31 +02:00
Version 0.0.5 - added SVG Support
This commit is contained in:
commit
0ed710a868
50
HISTORY
50
HISTORY
@ -7,14 +7,17 @@ VDR Plugin 'skindesigner' Revision History
|
|||||||
|
|
||||||
Version 0.0.2
|
Version 0.0.2
|
||||||
|
|
||||||
- added some more tokens with more detailed audio information in displaychannel -> statusinfo
|
- added some more tokens with more detailed audio information in
|
||||||
|
displaychannel -> statusinfo
|
||||||
- added hasVPS for current scheduling in displaychannel -> epginfo
|
- added hasVPS for current scheduling in displaychannel -> epginfo
|
||||||
- added common channel logo path for all skins
|
- added common channel logo path for all skins
|
||||||
- changed skin handling so that every skin is directly shown in VDR OSD Menu
|
- changed skin handling so that every skin is directly shown in VDR OSD Menu
|
||||||
- added Theme support, each skin can now have various themes
|
- added Theme support, each skin can now have various themes
|
||||||
- fixed a crash if no skindesigner skins are found and plugin setup menu is called from another skin
|
- fixed a crash if no skindesigner skins are found and plugin setup menu is
|
||||||
|
called from another skin
|
||||||
- added {durationhours} and {durationminutes} tokens in several view elements
|
- added {durationhours} and {durationminutes} tokens in several view elements
|
||||||
- added discusage icons to menu header view element so that it discusage can be displayed in every menu view
|
- added discusage icons to menu header view element so that it discusage can be
|
||||||
|
displayed in every menu view
|
||||||
- added numeric day, month and year tokens in different view elements
|
- added numeric day, month and year tokens in different view elements
|
||||||
- support for global variables type "double"
|
- support for global variables type "double"
|
||||||
- added setup options to configure rerun display behaviour
|
- added setup options to configure rerun display behaviour
|
||||||
@ -23,36 +26,46 @@ Version 0.0.2
|
|||||||
- added vps token in menudetailepg
|
- added vps token in menudetailepg
|
||||||
- implemented cSDDisplayMenu::GetTextAreaFont()
|
- implemented cSDDisplayMenu::GetTextAreaFont()
|
||||||
- introduced new viewelement audioinfo in displaychannel
|
- introduced new viewelement audioinfo in displaychannel
|
||||||
- added setup option to choose Menu Item display method between "at one go" and "after one another"
|
- added setup option to choose Menu Item display method between "at one go" and
|
||||||
- fixed bug that new skin was not properly loaded sometimes when skin was changed in OSD Setup menu
|
"after one another"
|
||||||
- fixed bug that new font was displayed first after VDR restart when font was changed in OSD Setup menu
|
- fixed bug that new skin was not properly loaded sometimes when skin was
|
||||||
- display always newest recording of folders in recordings list, thanks@ Lars Hanisch for providing the patch
|
changed in OSD Setup menu
|
||||||
|
- fixed bug that new font was displayed first after VDR restart when font was
|
||||||
|
changed in OSD Setup menu
|
||||||
|
- display always newest recording of folders in recordings list,
|
||||||
|
thanks@ Lars Hanisch for providing the patch
|
||||||
- added extented recording information
|
- added extented recording information
|
||||||
- added token {nummenuitem} as number of item for every list, value starts with 1
|
- added token {nummenuitem} as number of item for every list, value starts
|
||||||
|
with 1
|
||||||
- fixed bug that x and y of subviews was not respected
|
- fixed bug that x and y of subviews was not respected
|
||||||
- if a subview is completely not set in a skin, the default menu is used
|
- if a subview is completely not set in a skin, the default menu is used
|
||||||
- fixed a bug if displaydetailedtext is called without correct menucat (mailbox plugin)
|
- fixed a bug if displaydetailedtext is called without correct menucat (mailbox
|
||||||
|
plugin)
|
||||||
- implemented function drawslope, see Wiki for documentation
|
- implemented function drawslope, see Wiki for documentation
|
||||||
- using default menu list in case an invalid MenuCategory is set
|
- using default menu list in case an invalid MenuCategory is set
|
||||||
- added device info in displaychannel, example in metrixHD
|
- added device info in displaychannel, example in metrixHD
|
||||||
- improved menu icon display, additionally using menu cat
|
- improved menu icon display, additionally using menu cat
|
||||||
- changed devices list, device numbers start with 0
|
- changed devices list, device numbers start with 0
|
||||||
- fixed bug that hasposter is only true if poster really exists
|
- fixed bug that hasposter is only true if poster really exists
|
||||||
- no absolute pathes allowed for image type "image", path has to start with {ressourcedir}
|
- no absolute pathes allowed for image type "image", path has to start with
|
||||||
|
{ressourcedir}
|
||||||
|
|
||||||
Version 0.0.3
|
Version 0.0.3
|
||||||
|
|
||||||
- added tokens for current video and audio bitrate in displaychannel. Thx @rofafor for the original code
|
- added tokens for current video and audio bitrate in displaychannel.
|
||||||
|
Thx @rofafor for the original code
|
||||||
in the femon plugin and _Martin_ for extracting the code in skinflatplus
|
in the femon plugin and _Martin_ for extracting the code in skinflatplus
|
||||||
- changed skin metrixHD to display bitrate infos
|
- changed skin metrixHD to display bitrate infos
|
||||||
- added "active" Token for cutting marks so that a mark can be displayed in a dedicated way if current position
|
- added "active" Token for cutting marks so that a mark can be displayed in a
|
||||||
in replay exactly hits the mark
|
dedicated way if current position in replay exactly hits the mark
|
||||||
- added {channelname}, {channelid}, {channellogoexists} for all schedules list and current views
|
- added {channelname}, {channelid}, {channellogoexists} for all schedules list
|
||||||
|
and current views
|
||||||
- added printf function for <drawtext>, see Wiki for documentation
|
- added printf function for <drawtext>, see Wiki for documentation
|
||||||
- removed code for displaying bitrates in displaychannel again because of incompatibility with dvbapi Plugin
|
- removed code for displaying bitrates in displaychannel again because of
|
||||||
|
incompatibility with dvbapi Plugin
|
||||||
- optimized performance when creating a menu list
|
- optimized performance when creating a menu list
|
||||||
- fixed Bug that displaychannel was not shown after closing displaymenu with "backspace" (with active
|
- fixed Bug that displaychannel was not shown after closing displaymenu with
|
||||||
menuorg plugin)
|
"backspace" (with active menuorg plugin)
|
||||||
- fixed Bug with menuselection Patch
|
- fixed Bug with menuselection Patch
|
||||||
- added tokens {month}, {monthname} and {year} in displaymenutimers listitem and currentitem
|
- added tokens {month}, {monthname} and {year} in displaymenutimers listitem and currentitem
|
||||||
- added dedicated tokens for posters and banners in <srapercontent> in displaychannel and displayreplay
|
- added dedicated tokens for posters and banners in <srapercontent> in displaychannel and displayreplay
|
||||||
@ -62,3 +75,6 @@ Version 0.0.3
|
|||||||
|
|
||||||
Version 0.0.4
|
Version 0.0.4
|
||||||
|
|
||||||
|
- added SVG Support - thanks to Manuel Reimer!
|
||||||
|
|
||||||
|
Version 0.0.5
|
||||||
|
14
Makefile
14
Makefile
@ -3,9 +3,6 @@
|
|||||||
#
|
#
|
||||||
# $Id$ Makefile 1.0 2014/07/24 louis Exp $
|
# $Id$ Makefile 1.0 2014/07/24 louis Exp $
|
||||||
|
|
||||||
# External image lib to use: imagemagick, graphicsmagick
|
|
||||||
IMAGELIB = imagemagick
|
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
CONFIG := #-DDOPROFILE # enable profiling code
|
CONFIG := #-DDOPROFILE # enable profiling code
|
||||||
|
|
||||||
@ -50,13 +47,8 @@ DEFINES += $(shell xml2-config --cflags)
|
|||||||
|
|
||||||
INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
|
INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
|
||||||
|
|
||||||
ifeq ($(IMAGELIB), imagemagick)
|
INCLUDES += $(shell pkg-config --cflags librsvg-2.0 cairo-png) -ljpeg
|
||||||
INCLUDES += $(shell pkg-config --cflags Magick++)
|
LIBS += $(shell pkg-config --libs librsvg-2.0 cairo-png) -ljpeg
|
||||||
LIBS += $(shell pkg-config --libs Magick++)
|
|
||||||
else ifeq ($(IMAGELIB), graphicsmagick)
|
|
||||||
INCLUDES += $(shell pkg-config --cflags GraphicsMagick++)
|
|
||||||
LIBS += $(shell pkg-config --libs GraphicsMagick++)
|
|
||||||
endif
|
|
||||||
|
|
||||||
LIBS += $(shell xml2-config --libs)
|
LIBS += $(shell xml2-config --libs)
|
||||||
|
|
||||||
@ -74,8 +66,6 @@ OBJS = $(PLUGIN).o \
|
|||||||
libcore/pixmapcontainer.o \
|
libcore/pixmapcontainer.o \
|
||||||
libcore/fontmanager.o \
|
libcore/fontmanager.o \
|
||||||
libcore/imagecache.o \
|
libcore/imagecache.o \
|
||||||
libcore/imagemagickwrapper.o \
|
|
||||||
libcore/imagescaler.o \
|
|
||||||
libcore/helpers.o \
|
libcore/helpers.o \
|
||||||
libcore/imageloader.o \
|
libcore/imageloader.o \
|
||||||
libcore/recfolderinfo.o \
|
libcore/recfolderinfo.o \
|
||||||
|
57
README
57
README
@ -26,17 +26,17 @@ Requirements
|
|||||||
|
|
||||||
- VDR version >= 2.0.0
|
- VDR version >= 2.0.0
|
||||||
|
|
||||||
- Installed ImageMagick or GraphicsMagick for displaying png/jpg Icons, Channel Logos
|
- cairo
|
||||||
and EPG Images (configurable during make via IMAGELIB = imagemagick|graphicsmagick
|
|
||||||
parameter)
|
- librsvg-2
|
||||||
|
|
||||||
- libxml2
|
- libxml2
|
||||||
|
|
||||||
- for scaling the video picture to fit into the VDR menu window please use
|
- for scaling the video picture to fit into the VDR menu window please use
|
||||||
softhddevice plugin revision 87c1c7be (2013-01-01) or newer.
|
softhddevice plugin revision 87c1c7be (2013-01-01) or newer.
|
||||||
|
|
||||||
- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the schedules
|
- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the
|
||||||
menu with epgsearch
|
schedules menu with epgsearch
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
@ -53,8 +53,8 @@ XML skins and epg images. The following paths can be set at startup:
|
|||||||
-e path, --epgimages=path
|
-e path, --epgimages=path
|
||||||
Path to the epgimages (Default: <CacheDirectory>/epgimages/)
|
Path to the epgimages (Default: <CacheDirectory>/epgimages/)
|
||||||
|
|
||||||
ResourceDirectory and CacheDirectory are taken from your VDR configuration (make.config
|
ResourceDirectory and CacheDirectory are taken from your VDR configuration
|
||||||
or vdr.pc).
|
(make.config or vdr.pc).
|
||||||
|
|
||||||
During a "make install" the included skins are automatically copied from
|
During a "make install" the included skins are automatically copied from
|
||||||
<SkinSourceDirectory>/skins/ to the configured path.
|
<SkinSourceDirectory>/skins/ to the configured path.
|
||||||
@ -67,20 +67,21 @@ an suitable true color OSD.
|
|||||||
|
|
||||||
For Xineliboutput Users: Start vdr-sxfe with the --hud option enabled
|
For Xineliboutput Users: Start vdr-sxfe with the --hud option enabled
|
||||||
|
|
||||||
Since the default skin MetrixHD uses VDROpenSans as font which is not installed per
|
Since the default skin MetrixHD uses VDROpenSans as font which is not installed
|
||||||
default, you may want to install this font (included in <SkinSourceDirectory>/fonts/)
|
per default, you may want to install this font (included in
|
||||||
first. Otherwise the inside VDRs OSD menu configured vdrOsd Font is used as default.
|
<SkinSourceDirectory>/fonts/) first. Otherwise the inside VDRs OSD menu
|
||||||
|
configured vdrOsd Font is used as default.
|
||||||
|
|
||||||
Channel Logos
|
Channel Logos
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Since each XML skin is responsible for it's used channel logos, skindesigner searches
|
Since each XML skin is responsible for it's used channel logos, skindesigner
|
||||||
for channel logos only in the skin dependend directory
|
searches for channel logos only in the skin dependend directory
|
||||||
|
|
||||||
<ResourceDirectory>/plugins/skindesigner/skins/<skinname>/logos
|
<ResourceDirectory>/plugins/skindesigner/skins/<skinname>/logos
|
||||||
|
|
||||||
Each copy your used logos directly to this directory or set a symbolic link to a common
|
Each copy your used logos directly to this directory or set a symbolic link to
|
||||||
channellogo directory.
|
a common channellogo directory.
|
||||||
|
|
||||||
I recommend to use channel logos from https://github.com/3PO/Senderlogos
|
I recommend to use channel logos from https://github.com/3PO/Senderlogos
|
||||||
To download them just change in the directory you want to place the logos
|
To download them just change in the directory you want to place the logos
|
||||||
@ -90,16 +91,18 @@ An update of the logos can then be done with a "git pull" just inside this
|
|||||||
directory.
|
directory.
|
||||||
|
|
||||||
In this logo pack all files are named only with lower case letters.
|
In this logo pack all files are named only with lower case letters.
|
||||||
Skindesigner uses the channel name CONVERTED TO LOWER CASE LETTERS to search for an
|
Skindesigner uses the channel name CONVERTED TO LOWER CASE LETTERS to search
|
||||||
appropriate channel logo. With this, approximately 90% of the channel logos should work
|
for an appropriate channel logo. With this, approximately 90% of the channel
|
||||||
immediately after placing the channel logos in the correct place. So if you have to change
|
logos should work immediately after placing the channel logos in the correct
|
||||||
the name of a channel logo (may be by inserting a space or a hyphen) so that it fits to
|
place. So if you have to change the name of a channel logo (may be by inserting
|
||||||
the channel name, only use lower case letters, and not the name of the channel with upper
|
a space or a hyphen) so that it fits to the channel name, only use lower case
|
||||||
and lower letters as displayed inside VDR.
|
letters, and not the name of the channel with upper and lower letters as
|
||||||
If no logo is found for the channel name, additionally a search for a logo named as the
|
displayed inside VDR.
|
||||||
ChannelID is performed. Analog to the channel name the ChannelID is also converted to lower
|
If no logo is found for the channel name, additionally a search for a logo
|
||||||
case letters. This allows channel logos for channels with changing names (for instance
|
named as the ChannelID is performed. Analog to the channel name the ChannelID
|
||||||
Sky Feed Channels).
|
is also converted to lower case letters. This allows channel logos for channels
|
||||||
Additional hint: some channels have slashes in their name (in germany nick/comedy for instance).
|
with changing names (for instance Sky Feed Channels).
|
||||||
In this example, as a dirty hack just create a folder in your channel logo directory named
|
Additional hint: some channels have slashes in their name (in germany
|
||||||
"nick" and place an image named "comedy.png" inside this folder.
|
nick/comedy for instance).
|
||||||
|
In this example, as a dirty hack just create a folder in your channel logo
|
||||||
|
directory named "nick" and place an image named "comedy.png" inside this folder.
|
||||||
|
1
config.c
1
config.c
@ -7,7 +7,6 @@ cDesignerConfig::cDesignerConfig() {
|
|||||||
skinPathSet = false;
|
skinPathSet = false;
|
||||||
logoPathSet = false;
|
logoPathSet = false;
|
||||||
//Common
|
//Common
|
||||||
logoExtension = "png";
|
|
||||||
numLogosPerSizeInitial = 30;
|
numLogosPerSizeInitial = 30;
|
||||||
limitLogoCache = 1;
|
limitLogoCache = 1;
|
||||||
numLogosMax = 200;
|
numLogosMax = 200;
|
||||||
|
1
config.h
1
config.h
@ -48,7 +48,6 @@ public:
|
|||||||
void AddPlugin(string name, map < int, string > &menus);
|
void AddPlugin(string name, map < int, string > &menus);
|
||||||
void InitPluginIterator(void);
|
void InitPluginIterator(void);
|
||||||
map <int,string> *GetPluginTemplates(string &name);
|
map <int,string> *GetPluginTemplates(string &name);
|
||||||
cString logoExtension;
|
|
||||||
cString skinPath;
|
cString skinPath;
|
||||||
cString logoPath;
|
cString logoPath;
|
||||||
cString epgImagePath;
|
cString epgImagePath;
|
||||||
|
@ -7,14 +7,13 @@
|
|||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
using namespace Magick;
|
|
||||||
|
|
||||||
cMutex cImageCache::mutex;
|
cMutex cImageCache::mutex;
|
||||||
|
|
||||||
string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
|
string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
|
||||||
"OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
|
"OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
|
||||||
|
|
||||||
cImageCache::cImageCache() : cImageMagickWrapper() {
|
cImageCache::cImageCache() {
|
||||||
tempStaticLogo = NULL;
|
tempStaticLogo = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,27 +140,19 @@ bool cImageCache::LogoExists(string channelID) {
|
|||||||
if (!channel)
|
if (!channel)
|
||||||
return false;
|
return false;
|
||||||
string logoLower = StrToLowerCase(channel->Name());
|
string logoLower = StrToLowerCase(channel->Name());
|
||||||
string logoExt = *config.logoExtension;
|
|
||||||
bool logoExists = FileExists(logoPath.c_str(), logoLower, logoExt);
|
return (FileExists(logoPath.c_str(), logoLower, "svg") ||
|
||||||
if (logoExists) {
|
FileExists(logoPath.c_str(), logoLower, "png") ||
|
||||||
return true;
|
FileExists(logoPath.c_str(), channelID, "svg") ||
|
||||||
}
|
FileExists(logoPath.c_str(), channelID, "png"));
|
||||||
logoExists = FileExists(logoPath.c_str(), channelID, logoExt);
|
|
||||||
if (logoExists) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cImageCache::SeparatorLogoExists(string name) {
|
bool cImageCache::SeparatorLogoExists(string name) {
|
||||||
string separatorPath = *cString::sprintf("%sseparatorlogos/", logoPath.c_str());
|
string separatorPath = *cString::sprintf("%sseparatorlogos/", logoPath.c_str());
|
||||||
string nameLower = StrToLowerCase(name.c_str());
|
string nameLower = StrToLowerCase(name.c_str());
|
||||||
string logoExt = *config.logoExtension;
|
|
||||||
bool logoExists = FileExists(separatorPath, nameLower, logoExt);
|
return (FileExists(separatorPath, nameLower, "svg") ||
|
||||||
if (logoExists) {
|
FileExists(separatorPath, nameLower, "png"));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
|
void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
|
||||||
@ -312,18 +303,17 @@ cImage *cImageCache::GetSkinpart(string name, int width, int height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cImageCache::LoadIcon(eImageType type, string name) {
|
bool cImageCache::LoadIcon(eImageType type, string name) {
|
||||||
bool success = false;
|
|
||||||
cString subdir("");
|
cString subdir("");
|
||||||
if (type == itMenuIcon)
|
if (type == itMenuIcon)
|
||||||
subdir = "menuicons";
|
subdir = "menuicons";
|
||||||
else if (type == itIcon)
|
else if (type == itIcon)
|
||||||
subdir = "icons";
|
subdir = "icons";
|
||||||
cString subIconPath = cString::sprintf("%s%s/", iconPath.c_str(), *subdir);
|
cString subIconPath = cString::sprintf("%s%s/", iconPath.c_str(), *subdir);
|
||||||
success = LoadImage(name, *subIconPath, "png");
|
|
||||||
if (success) {
|
if (FileExists(*subIconPath, name, "svg"))
|
||||||
return true;
|
return LoadImage(*subIconPath, name, "svg");
|
||||||
}
|
else
|
||||||
return false;
|
return LoadImage(*subIconPath, name, "png");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cImageCache::LoadLogo(const cChannel *channel) {
|
bool cImageCache::LoadLogo(const cChannel *channel) {
|
||||||
@ -331,33 +321,33 @@ bool cImageCache::LoadLogo(const cChannel *channel) {
|
|||||||
return false;
|
return false;
|
||||||
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
|
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
|
||||||
string logoLower = StrToLowerCase(channel->Name());
|
string logoLower = StrToLowerCase(channel->Name());
|
||||||
bool success = false;
|
|
||||||
success = LoadImage(channelID.c_str(), logoPath.c_str(), *config.logoExtension);
|
if (FileExists(logoPath.c_str(), channelID.c_str(), "svg"))
|
||||||
if (success)
|
return LoadImage(logoPath.c_str(), channelID.c_str(), "svg");
|
||||||
return true;
|
if (FileExists(logoPath.c_str(), channelID.c_str(), "png"))
|
||||||
success = LoadImage(logoLower.c_str(), logoPath.c_str(), *config.logoExtension);
|
return LoadImage(logoPath.c_str(), channelID.c_str(), "png");
|
||||||
if (success)
|
if (FileExists(logoPath.c_str(), logoLower.c_str(), "svg"))
|
||||||
return true;
|
return LoadImage(logoPath.c_str(), logoLower.c_str(), "svg");
|
||||||
|
if (FileExists(logoPath.c_str(), logoLower.c_str(), "png"))
|
||||||
|
return LoadImage(logoPath.c_str(), logoLower.c_str(), "png");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cImageCache::LoadSeparatorLogo(string name) {
|
bool cImageCache::LoadSeparatorLogo(string name) {
|
||||||
cString separatorPath = cString::sprintf("%sseparatorlogos/", logoPath.c_str());
|
string separatorPath = *cString::sprintf("%sseparatorlogos/", logoPath.c_str());
|
||||||
string nameLower = StrToLowerCase(name.c_str());
|
string nameLower = StrToLowerCase(name.c_str());
|
||||||
bool success = false;
|
if (FileExists(separatorPath, nameLower.c_str(), "svg"))
|
||||||
success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
|
return LoadImage(separatorPath, nameLower.c_str(), "svg");
|
||||||
if (success)
|
else
|
||||||
return true;
|
return LoadImage(separatorPath, nameLower.c_str(), "png");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cImageCache::LoadSkinpart(string name) {
|
bool cImageCache::LoadSkinpart(string name) {
|
||||||
bool success = false;
|
if (FileExists(skinPartsPath.c_str(), name, "svg"))
|
||||||
success = LoadImage(name, skinPartsPath.c_str(), "png");
|
return LoadImage(skinPartsPath.c_str(), name, "svg");
|
||||||
if (success) {
|
else
|
||||||
return true;
|
return LoadImage(skinPartsPath.c_str(), name, "png");
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cImageCache::Clear(void) {
|
void cImageCache::Clear(void) {
|
||||||
|
@ -5,14 +5,11 @@
|
|||||||
|
|
||||||
#include <vdr/osd.h>
|
#include <vdr/osd.h>
|
||||||
#include <vdr/skins.h>
|
#include <vdr/skins.h>
|
||||||
#include <Magick++.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "imagemagickwrapper.h"
|
#include "imageloader.h"
|
||||||
#include "../libtemplate/templatefunction.h"
|
#include "../libtemplate/templatefunction.h"
|
||||||
|
|
||||||
using namespace Magick;
|
class cImageCache : public cImageLoader {
|
||||||
|
|
||||||
class cImageCache : public cImageMagickWrapper {
|
|
||||||
public:
|
public:
|
||||||
cImageCache();
|
cImageCache();
|
||||||
~cImageCache();
|
~cImageCache();
|
||||||
|
@ -1,62 +1,400 @@
|
|||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "imageloader.h"
|
#include "imageloader.h"
|
||||||
#include <math.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace Magick;
|
cImageLoader::cImageLoader() {
|
||||||
|
importer = NULL;
|
||||||
cImageLoader::cImageLoader() : cImageMagickWrapper() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cImageLoader::~cImageLoader() {
|
cImageLoader::~cImageLoader() {
|
||||||
|
delete(importer);
|
||||||
}
|
}
|
||||||
|
|
||||||
cImage cImageLoader::GetImage() {
|
cImage *cImageLoader::CreateImage(int width, int height, bool preserveAspect) {
|
||||||
return CreateImageCopy();
|
if (!importer)
|
||||||
}
|
return NULL;
|
||||||
|
|
||||||
bool cImageLoader::LoadImage(const char *path, int width, int height) {
|
int w, h;
|
||||||
if (cImageMagickWrapper::LoadImage(path)) {
|
importer->GetImageSize(w, h);
|
||||||
buffer.sample(Geometry(width, height));
|
if (width == 0)
|
||||||
return true;
|
width = w;
|
||||||
|
if (height == 0)
|
||||||
|
height = h;
|
||||||
|
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||||
|
|
||||||
|
cairo_t *cr;
|
||||||
|
cr = cairo_create(surface);
|
||||||
|
|
||||||
|
double sx = width / (double)w;
|
||||||
|
double sy = height / (double)h;
|
||||||
|
if (preserveAspect) {
|
||||||
|
double tx = 0;
|
||||||
|
double ty = 0;
|
||||||
|
if (sx < sy) {
|
||||||
|
sy = sx;
|
||||||
|
ty = (height - h * sy) / 2;
|
||||||
|
}
|
||||||
|
if (sy < sx) {
|
||||||
|
sx = sy;
|
||||||
|
tx = (width - w * sx) / 2;
|
||||||
|
}
|
||||||
|
cairo_translate(cr, tx, ty);
|
||||||
}
|
}
|
||||||
return false;
|
cairo_scale(cr, sx, sy);
|
||||||
|
|
||||||
|
importer->DrawToCairo(cr);
|
||||||
|
|
||||||
|
cairo_status_t status = cairo_status(cr);
|
||||||
|
if (status && config.debugImageLoading)
|
||||||
|
dsyslog("skindesigner: Cairo CreateImage Error %s", cairo_status_to_string(status));
|
||||||
|
|
||||||
|
unsigned char *data = cairo_image_surface_get_data(surface);
|
||||||
|
cImage *image = new cImage(cSize(width, height), (tColor*)data);
|
||||||
|
|
||||||
|
cairo_destroy(cr);
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cImageLoader::LoadImage(const char *fullpath) {
|
||||||
|
if ((fullpath == NULL) || (strlen(fullpath) < 5))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (config.debugImageLoading)
|
||||||
|
dsyslog("skindesigner: trying to load: %s", fullpath);
|
||||||
|
|
||||||
|
delete(importer);
|
||||||
|
importer = NULL;
|
||||||
|
|
||||||
|
if (endswith(fullpath, ".png"))
|
||||||
|
importer = new cImageImporterPNG;
|
||||||
|
else if (endswith(fullpath, ".svg"))
|
||||||
|
importer = new cImageImporterSVG;
|
||||||
|
else if (endswith(fullpath, ".jpg"))
|
||||||
|
importer = new cImageImporterJPG;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return importer->LoadImage(fullpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just a different way to call LoadImage. Calls the above one.
|
||||||
|
bool cImageLoader::LoadImage(std::string Path, std::string FileName, std::string Extension) {
|
||||||
|
std::stringstream sstrImgFile;
|
||||||
|
sstrImgFile << Path << FileName << "." << Extension;
|
||||||
|
std::string imgFile = sstrImgFile.str();
|
||||||
|
return LoadImage(imgFile.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
|
void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
|
||||||
cString logoPath;
|
cString logoPath;
|
||||||
cString logoPathSkin = cString::sprintf("%s%s/themes/%s/logos/", *config.skinPath, Setup.OSDSkin, Setup.OSDTheme);
|
cString logoPathSkin = cString::sprintf("%s%s/themes/%s/logos/", *config.skinPath, Setup.OSDSkin, Setup.OSDTheme);
|
||||||
if (FolderExists(*logoPathSkin)) {
|
|
||||||
|
if (FolderExists(*logoPathSkin))
|
||||||
logoPath = logoPathSkin;
|
logoPath = logoPathSkin;
|
||||||
} else {
|
else
|
||||||
logoPath = config.logoPath;
|
logoPath = config.logoPath;
|
||||||
}
|
|
||||||
cString logoExt = config.logoExtension;
|
|
||||||
DIR *folder = NULL;
|
DIR *folder = NULL;
|
||||||
struct dirent *file;
|
struct dirent *file;
|
||||||
folder = opendir(logoPath);
|
folder = opendir(logoPath);
|
||||||
if (!folder) {
|
if (!folder)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
while (file = readdir(folder)) {
|
while ( (file = readdir(folder)) ) {
|
||||||
if (endswith(file->d_name, *logoExt)) {
|
if (endswith(file->d_name, ".png") ||
|
||||||
|
endswith(file->d_name, ".svg")) {
|
||||||
std::stringstream filePath;
|
std::stringstream filePath;
|
||||||
filePath << *logoPath << file->d_name;
|
filePath << *logoPath << file->d_name;
|
||||||
Image logo;
|
if (LoadImage(filePath.str().c_str())) {
|
||||||
try {
|
int logoWidth = 0;
|
||||||
logo.read(filePath.str().c_str());
|
int logoHeight = 0;
|
||||||
Geometry g = logo.size();
|
importer->GetImageSize(logoWidth, logoHeight);
|
||||||
int logoWidth = g.width();
|
|
||||||
int logoHeight = g.height();
|
|
||||||
if (logoWidth > 0 && logoHeight > 0) {
|
if (logoWidth > 0 && logoHeight > 0) {
|
||||||
width = logoWidth;
|
width = logoWidth;
|
||||||
height = logoHeight;
|
height = logoHeight;
|
||||||
|
delete(importer);
|
||||||
|
importer = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch( ... ) { }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Image importer for PNG
|
||||||
|
//
|
||||||
|
|
||||||
|
cImageImporterPNG::cImageImporterPNG() {
|
||||||
|
surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cImageImporterPNG::~cImageImporterPNG() {
|
||||||
|
if (surface)
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cImageImporterPNG::LoadImage(const char *path) {
|
||||||
|
if (surface)
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
|
surface = cairo_image_surface_create_from_png(path);
|
||||||
|
|
||||||
|
if (cairo_surface_status(surface)) {
|
||||||
|
if (config.debugImageLoading)
|
||||||
|
dsyslog("skindesigner: Cairo LoadImage Error: %s", cairo_status_to_string(cairo_surface_status(surface)));
|
||||||
|
surface = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterPNG::DrawToCairo(cairo_t *cr) {
|
||||||
|
if (surface) {
|
||||||
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
cairo_paint(cr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterPNG::GetImageSize(int &width, int &height) {
|
||||||
|
if (surface) {
|
||||||
|
width = cairo_image_surface_get_width(surface);
|
||||||
|
height = cairo_image_surface_get_height(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Image importer for SVG
|
||||||
|
//
|
||||||
|
|
||||||
|
cImageImporterSVG::cImageImporterSVG() {
|
||||||
|
handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cImageImporterSVG::~cImageImporterSVG() {
|
||||||
|
if (handle) {
|
||||||
|
rsvg_handle_close(handle, NULL);
|
||||||
|
g_object_unref(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cImageImporterSVG::LoadImage(const char *path) {
|
||||||
|
if (handle) {
|
||||||
|
rsvg_handle_close(handle, NULL);
|
||||||
|
g_object_unref(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
handle = rsvg_handle_new_from_file(path, &error);
|
||||||
|
if (!handle) {
|
||||||
|
if (config.debugImageLoading && error) {
|
||||||
|
dsyslog("skindesigner: RSVG Error: %s", error->message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 90 dpi is the hardcoded default setting of the Inkscape SVG editor
|
||||||
|
rsvg_handle_set_dpi(handle, 90);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterSVG::DrawToCairo(cairo_t *cr) {
|
||||||
|
if (handle)
|
||||||
|
rsvg_handle_render_cairo(handle, cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterSVG::GetImageSize(int &width, int &height) {
|
||||||
|
if (handle) {
|
||||||
|
RsvgDimensionData dim;
|
||||||
|
rsvg_handle_get_dimensions(handle, &dim);
|
||||||
|
width = dim.width;
|
||||||
|
height = dim.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Image importer for JPG
|
||||||
|
//
|
||||||
|
|
||||||
|
struct my_error_mgr {
|
||||||
|
struct jpeg_error_mgr pub; // "public" fields
|
||||||
|
jmp_buf setjmp_buffer; // for return to caller
|
||||||
|
};
|
||||||
|
|
||||||
|
METHODDEF(void)
|
||||||
|
my_error_exit(j_common_ptr cinfo) {
|
||||||
|
// cinfo->err really points to a my_error_mgr struct, so coerce pointer
|
||||||
|
my_error_mgr *myerr = (my_error_mgr*) cinfo->err;
|
||||||
|
|
||||||
|
// Always display the message.
|
||||||
|
(*cinfo->err->output_message) (cinfo);
|
||||||
|
|
||||||
|
// Return control to the setjmp point
|
||||||
|
longjmp(myerr->setjmp_buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHODDEF(void)
|
||||||
|
my_output_message(j_common_ptr cinfo) {
|
||||||
|
char buf[JMSG_LENGTH_MAX];
|
||||||
|
cinfo->err->format_message(cinfo, buf);
|
||||||
|
if (config.debugImageLoading)
|
||||||
|
dsyslog("skindesigner: libjpeg error: %s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
cImageImporterJPG::cImageImporterJPG() {
|
||||||
|
cinfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cImageImporterJPG::~cImageImporterJPG() {
|
||||||
|
if (cinfo) {
|
||||||
|
jpeg_destroy_decompress(cinfo);
|
||||||
|
free(cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cImageImporterJPG::LoadImage(const char *path) {
|
||||||
|
if (cinfo) {
|
||||||
|
jpeg_destroy_decompress(cinfo);
|
||||||
|
free(cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
cinfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open input file
|
||||||
|
if ((infile = fopen(path, "rb")) == NULL) {
|
||||||
|
if (config.debugImageLoading)
|
||||||
|
dsyslog("skindesigner: Can't open %s", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate space for our decompress struct
|
||||||
|
cinfo = (j_decompress_ptr)malloc(sizeof(struct jpeg_decompress_struct));
|
||||||
|
|
||||||
|
// We set up the normal JPEG error routines, then override error_exit
|
||||||
|
// and output_message.
|
||||||
|
struct my_error_mgr jerr;
|
||||||
|
cinfo->err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = my_error_exit;
|
||||||
|
jerr.pub.output_message = my_output_message;
|
||||||
|
// Establish the setjmp return context for my_error_exit to use.
|
||||||
|
if (setjmp(jerr.setjmp_buffer)) {
|
||||||
|
// If we get here, the JPEG code has signaled an error.
|
||||||
|
jpeg_destroy_decompress(cinfo);
|
||||||
|
free(cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
cinfo = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can initialize the JPEG decompression object.
|
||||||
|
jpeg_create_decompress(cinfo);
|
||||||
|
|
||||||
|
// Step 2: specify data source (eg, a file)
|
||||||
|
jpeg_stdio_src(cinfo, infile);
|
||||||
|
|
||||||
|
// Step 3: read file parameters with jpeg_read_header()
|
||||||
|
(void) jpeg_read_header(cinfo, TRUE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterJPG::DrawToCairo(cairo_t *cr) {
|
||||||
|
if (!cinfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned char *bmp_buffer = NULL;
|
||||||
|
|
||||||
|
// Re-establish error handling. We have to do this again as the saved
|
||||||
|
// calling environment of "LoadImage" is invalid if we reach here!
|
||||||
|
struct my_error_mgr jerr;
|
||||||
|
cinfo->err = jpeg_std_error(&jerr.pub);
|
||||||
|
jerr.pub.error_exit = my_error_exit;
|
||||||
|
jerr.pub.output_message = my_output_message;
|
||||||
|
if (setjmp(jerr.setjmp_buffer)) {
|
||||||
|
jpeg_destroy_decompress(cinfo);
|
||||||
|
free(cinfo);
|
||||||
|
fclose(infile);
|
||||||
|
free(bmp_buffer);
|
||||||
|
cinfo = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: set parameters for decompression
|
||||||
|
cinfo->out_color_space = JCS_RGB;
|
||||||
|
|
||||||
|
// Step 5: Start decompressor
|
||||||
|
(void) jpeg_start_decompress(cinfo);
|
||||||
|
|
||||||
|
// Allocate buffer. Directly allocate the space needed for ARGB
|
||||||
|
unsigned int width = cinfo->output_width;
|
||||||
|
unsigned int height = cinfo->output_height;
|
||||||
|
bmp_buffer = (unsigned char*)malloc(width * height * 4);
|
||||||
|
|
||||||
|
// Step 6: while (scan lines remain to be read)
|
||||||
|
int jpg_stride = width * cinfo->output_components;
|
||||||
|
while (cinfo->output_scanline < height) {
|
||||||
|
unsigned char *buffer_array[1];
|
||||||
|
buffer_array[0] = bmp_buffer + (cinfo->output_scanline) * jpg_stride;
|
||||||
|
jpeg_read_scanlines(cinfo, buffer_array, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Finish decompression.
|
||||||
|
(void)jpeg_finish_decompress(cinfo);
|
||||||
|
|
||||||
|
// Cleanup. In this "ImageImporter" we clean up everything in "DrawToCairo"
|
||||||
|
// as I'm not really sure whether we are able to draw a second time.
|
||||||
|
fclose(infile);
|
||||||
|
jpeg_destroy_decompress(cinfo);
|
||||||
|
free(cinfo);
|
||||||
|
cinfo = NULL;
|
||||||
|
|
||||||
|
// --> At this point we have raw RGB data in bmp_buffer
|
||||||
|
|
||||||
|
// Do some ugly byte shifting.
|
||||||
|
// Byte order in libjpeg: RGB
|
||||||
|
// Byte order in cairo and VDR: BGRA
|
||||||
|
unsigned char temp[3];
|
||||||
|
for (int index = (width * height) - 1; index >= 0; index--) {
|
||||||
|
unsigned char *target = bmp_buffer + (index * 4);
|
||||||
|
unsigned char *source = bmp_buffer + (index * 3);
|
||||||
|
memcpy(&temp[0], source + 2, 1);
|
||||||
|
memcpy(&temp[1], source + 1, 1);
|
||||||
|
memcpy(&temp[2], source, 1);
|
||||||
|
memcpy(target, &temp, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new Cairo surface from our raw image data
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
surface = cairo_image_surface_create_for_data(bmp_buffer,
|
||||||
|
CAIRO_FORMAT_RGB24,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
width * 4);
|
||||||
|
|
||||||
|
// Draw surface to Cairo
|
||||||
|
if (surface) {
|
||||||
|
cairo_set_source_surface(cr, surface, 0, 0);
|
||||||
|
cairo_paint(cr);
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free our memory
|
||||||
|
free(bmp_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cImageImporterJPG::GetImageSize(int &width, int &height) {
|
||||||
|
if (cinfo) {
|
||||||
|
width = cinfo->image_width;
|
||||||
|
height = cinfo->image_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,23 +1,82 @@
|
|||||||
#ifndef __NOPACITY_IMAGELOADER_H
|
#ifndef __NOPACITY_IMAGELOADER_H
|
||||||
#define __NOPACITY_IMAGELOADER_H
|
#define __NOPACITY_IMAGELOADER_H
|
||||||
|
|
||||||
#define X_DISPLAY_MISSING
|
#include <cairo.h>
|
||||||
|
#include <librsvg/rsvg.h>
|
||||||
|
#ifndef LIBRSVG_VERSION // Workaround for librsvg < 2.36.2
|
||||||
|
#include <librsvg/rsvg-cairo.h>
|
||||||
|
#endif
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
#include <vdr/osd.h>
|
#include <vdr/osd.h>
|
||||||
#include <vdr/skins.h>
|
#include <vdr/tools.h>
|
||||||
#include <Magick++.h>
|
|
||||||
#include "imagemagickwrapper.h"
|
|
||||||
|
|
||||||
using namespace Magick;
|
//
|
||||||
|
// Image importers
|
||||||
|
//
|
||||||
|
class cImageImporter {
|
||||||
|
public:
|
||||||
|
cImageImporter() {};
|
||||||
|
virtual ~cImageImporter() {};
|
||||||
|
virtual bool LoadImage(const char *path) { return false; };
|
||||||
|
virtual void DrawToCairo(cairo_t *cr) {};
|
||||||
|
virtual void GetImageSize(int &width, int &height) {};
|
||||||
|
};
|
||||||
|
|
||||||
class cImageLoader : public cImageMagickWrapper {
|
// Image importer for PNG
|
||||||
|
class cImageImporterPNG : public cImageImporter {
|
||||||
|
public:
|
||||||
|
cImageImporterPNG();
|
||||||
|
~cImageImporterPNG();
|
||||||
|
bool LoadImage(const char *path);
|
||||||
|
void DrawToCairo(cairo_t *cr);
|
||||||
|
void GetImageSize(int &width, int &height);
|
||||||
|
private:
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Image importer for SVG
|
||||||
|
class cImageImporterSVG : public cImageImporter {
|
||||||
|
public:
|
||||||
|
cImageImporterSVG();
|
||||||
|
~cImageImporterSVG();
|
||||||
|
bool LoadImage(const char *path);
|
||||||
|
void DrawToCairo(cairo_t *cr);
|
||||||
|
void GetImageSize(int &width, int &height);
|
||||||
|
private:
|
||||||
|
RsvgHandle *handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Image importer for JPG
|
||||||
|
#if BITS_IN_JSAMPLE != 8
|
||||||
|
#error libjpeg has to be compiled with 8-bit samples!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class cImageImporterJPG : public cImageImporter {
|
||||||
|
public:
|
||||||
|
cImageImporterJPG();
|
||||||
|
~cImageImporterJPG();
|
||||||
|
bool LoadImage(const char *path);
|
||||||
|
void DrawToCairo(cairo_t *cr);
|
||||||
|
void GetImageSize(int &width, int &height);
|
||||||
|
private:
|
||||||
|
j_decompress_ptr cinfo;
|
||||||
|
FILE *infile;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Image loader class
|
||||||
|
//
|
||||||
|
class cImageLoader {
|
||||||
|
private:
|
||||||
|
cImageImporter *importer;
|
||||||
public:
|
public:
|
||||||
cImageLoader();
|
cImageLoader();
|
||||||
~cImageLoader();
|
virtual ~cImageLoader();
|
||||||
cImage GetImage();
|
cImage *CreateImage(int width, int height, bool preserveAspect = true);
|
||||||
bool LoadImage(const char *path, int width, int height);
|
bool LoadImage(std::string Path, std::string FileName, std::string Extension);
|
||||||
|
bool LoadImage(const char *fullpath);
|
||||||
void DeterminateChannelLogoSize(int &width, int &height);
|
void DeterminateChannelLogoSize(int &width, int &height);
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__NOPACITY_IMAGELOADER_H
|
#endif //__NOPACITY_IMAGELOADER_H
|
||||||
|
@ -1,162 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
#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
|
|
@ -1,149 +0,0 @@
|
|||||||
|
|
||||||
#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++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
#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
|
|
||||||
|
|
@ -13,7 +13,6 @@ cXmlParser::cXmlParser(void) {
|
|||||||
root = NULL;
|
root = NULL;
|
||||||
ctxt = NULL;
|
ctxt = NULL;
|
||||||
|
|
||||||
xmlInitParser();
|
|
||||||
initGenericErrorDefaultFunc(NULL);
|
initGenericErrorDefaultFunc(NULL);
|
||||||
xmlSetStructuredErrorFunc(NULL, SkinDesignerXMLErrorHandler);
|
xmlSetStructuredErrorFunc(NULL, SkinDesignerXMLErrorHandler);
|
||||||
ctxt = xmlNewParserCtxt();
|
ctxt = xmlNewParserCtxt();
|
||||||
@ -22,7 +21,6 @@ cXmlParser::cXmlParser(void) {
|
|||||||
cXmlParser::~cXmlParser() {
|
cXmlParser::~cXmlParser() {
|
||||||
DeleteDocument();
|
DeleteDocument();
|
||||||
xmlFreeParserCtxt(ctxt);
|
xmlFreeParserCtxt(ctxt);
|
||||||
xmlCleanupParser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
@ -801,3 +799,11 @@ bool cXmlParser::DebugViewElement(xmlNodePtr node) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cXmlParser::InitLibXML() {
|
||||||
|
xmlInitParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cXmlParser::CleanupLibXML() {
|
||||||
|
xmlCleanupParser();
|
||||||
|
}
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
bool ParsePluginView(string plugName, int templateNumber);
|
bool ParsePluginView(string plugName, int templateNumber);
|
||||||
bool ParseGlobals(void);
|
bool ParseGlobals(void);
|
||||||
void DeleteDocument(void);
|
void DeleteDocument(void);
|
||||||
|
static void InitLibXML();
|
||||||
|
static void CleanupLibXML();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__XMLPARSER_H
|
#endif //__XMLPARSER_H
|
@ -19,7 +19,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const char *VERSION = "0.0.4";
|
static const char *VERSION = "0.0.5";
|
||||||
static const char *DESCRIPTION = "SkinDesigner";
|
static const char *DESCRIPTION = "SkinDesigner";
|
||||||
static const char *MAINMENUENTRY = "Skin Designer";
|
static const char *MAINMENUENTRY = "Skin Designer";
|
||||||
|
|
||||||
@ -95,6 +95,7 @@ bool cPluginSkinDesigner::Initialize(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginSkinDesigner::Start(void) {
|
bool cPluginSkinDesigner::Start(void) {
|
||||||
|
cXmlParser::InitLibXML();
|
||||||
bool trueColorAvailable = true;
|
bool trueColorAvailable = true;
|
||||||
if (!cOsdProvider::SupportsTrueColor()) {
|
if (!cOsdProvider::SupportsTrueColor()) {
|
||||||
esyslog("skindesigner: No TrueColor OSD found! Using default Skin LCARS!");
|
esyslog("skindesigner: No TrueColor OSD found! Using default Skin LCARS!");
|
||||||
@ -121,6 +122,7 @@ bool cPluginSkinDesigner::Start(void) {
|
|||||||
void cPluginSkinDesigner::Stop(void) {
|
void cPluginSkinDesigner::Stop(void) {
|
||||||
delete imgCache;
|
delete imgCache;
|
||||||
delete fontManager;
|
delete fontManager;
|
||||||
|
cXmlParser::CleanupLibXML();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPluginSkinDesigner::Housekeeping(void) {
|
void cPluginSkinDesigner::Housekeeping(void) {
|
||||||
|
64
skins/metrixhd/themes/default/icons/ico_hd_off.svg
Normal file
64
skins/metrixhd/themes/default/icons/ico_hd_off.svg
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.5 r10040"
|
||||||
|
width="49"
|
||||||
|
height="24"
|
||||||
|
sodipodi:docname="ico_hd_off.svg">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1769"
|
||||||
|
inkscape:window-height="1195"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="6.9532167"
|
||||||
|
inkscape:cx="-12.199961"
|
||||||
|
inkscape:cy="10.824729"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196081000000004;opacity:0.4;fill-opacity:1"
|
||||||
|
d="m 3.7627119,1.5762712 5.8474576,0 -1.220339,6.9661017 9.1525425,-0.050847 0.966102,-7.0677966 6.016389,0.014893 -2.965542,21.1376493 -5.993831,0.06883 1.20853,-8.712893 -9.3502922,0.08899 -1.6652543,8.491525 -5.30084738,0.06356 z"
|
||||||
|
id="path3759"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078000000000;opacity:0.4"
|
||||||
|
d="m 28.398305,1.3728813 15.991526,0 C 46.277579,1.243275 49.255354,2.7574438 48.61017,8.0338983 47.616873,15.342244 46.343401,22.177506 41.288136,22.627119 L 24.915254,22.525424 27.20339,8.7966102 l 5.898305,-0.025424 -1.576271,9.5338988 7.677966,0 c 2.596312,0.118399 3.234177,-5.226757 3.457627,-7.90678 0.408058,-3.1501646 0.153706,-4.2577277 -1.420115,-4.3115034 L 27.61017,6.152542 z"
|
||||||
|
id="path3767"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
64
skins/metrixhd/themes/default/icons/ico_hd_on.svg
Normal file
64
skins/metrixhd/themes/default/icons/ico_hd_on.svg
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.5 r10040"
|
||||||
|
width="49"
|
||||||
|
height="24"
|
||||||
|
sodipodi:docname="ico_hd_on.svg">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1769"
|
||||||
|
inkscape:window-height="1195"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="6.9532167"
|
||||||
|
inkscape:cx="19.799617"
|
||||||
|
inkscape:cy="10.824729"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196081000000004;opacity:1;fill-opacity:1"
|
||||||
|
d="m 3.7627119,1.5762712 5.8474576,0 -1.220339,6.9661017 9.1525425,-0.050847 0.966102,-7.0677966 6.016389,0.014893 -2.965542,21.1376493 -5.993831,0.06883 1.20853,-8.712893 -9.3502922,0.08899 -1.6652543,8.491525 -5.30084738,0.06356 z"
|
||||||
|
id="path3759"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078000000000"
|
||||||
|
d="m 28.398305,1.3728813 15.991526,0 C 46.277579,1.243275 49.255354,2.7574438 48.61017,8.0338983 47.616873,15.342244 46.343401,22.177506 41.288136,22.627119 L 24.915254,22.525424 27.20339,8.7966102 l 5.898305,-0.025424 -1.576271,9.5338988 7.677966,0 c 2.596312,0.118399 3.234177,-5.226757 3.457627,-7.90678 0.408058,-3.1501646 0.153706,-4.2577277 -1.420115,-4.3115034 L 27.61017,6.152542 z"
|
||||||
|
id="path3767"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
58
skins/metrixhd/themes/default/icons/ico_widescreen_off.svg
Normal file
58
skins/metrixhd/themes/default/icons/ico_widescreen_off.svg
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.5 r10040"
|
||||||
|
width="43"
|
||||||
|
height="23"
|
||||||
|
sodipodi:docname="ico_widescreen_off.svg">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2048"
|
||||||
|
inkscape:window-height="1481"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16"
|
||||||
|
inkscape:cx="-4.8693805"
|
||||||
|
inkscape:cy="19.882154"
|
||||||
|
inkscape:window-x="-2"
|
||||||
|
inkscape:window-y="-3"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<path
|
||||||
|
id="path3834"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:0.4"
|
||||||
|
d="M 26.31204,9.2549017 29.307138,8.946193 c 1.930719,-0.2361949 1.627499,7.01011 -0.03235,6.862976 L 26.236601,15.553807 z M 0,0 0,23 c 15.021262,-4.846203 26.918346,-4.787057 43,0 L 43,0 C 26.964088,7.5152881 15.064204,7.6359799 0,0 z m 41.5625,2.59375 0,2.90625 -3.96875,1.46875 0,3.6875 3.40625,-0.0625 0,2.4375 -3.40625,0 0,3.65625 4.15625,1.125 0,2.90625 -6.71875,-1.6875 0,-13.875 z M 1.90625,2.8125 4.59375,4.03125 6.375,14.5625 8.03125,5.3125 10.625,6.125 l 2.34375,8.5 1.5,-7.65625 L 17.0625,7.3125 14.71875,17.75 11.34375,18.21875 9.5,10.3125 l -1.53125,8.53125 -3.5,0.8125 z M 30,6.75 c 4.450278,0.058184 3.725392,11.914384 -0.5625,11.3125 l -5.6875,-0.53125 0.0625,-10.0625 5.75,-0.6875 C 29.716868,6.7577574 29.856443,6.7481231 30,6.75 z m -11.4375,0.71875 2.625,0.09375 0,9.84375 -2.625,0.09375 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccsccccsccccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
58
skins/metrixhd/themes/default/icons/ico_widescreen_on.svg
Normal file
58
skins/metrixhd/themes/default/icons/ico_widescreen_on.svg
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.5 r10040"
|
||||||
|
width="43"
|
||||||
|
height="23"
|
||||||
|
sodipodi:docname="ico_widescreen_on.png">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2048"
|
||||||
|
inkscape:window-height="1481"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16"
|
||||||
|
inkscape:cx="9.0368695"
|
||||||
|
inkscape:cy="19.882154"
|
||||||
|
inkscape:window-x="-2"
|
||||||
|
inkscape:window-y="-3"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg2" />
|
||||||
|
<path
|
||||||
|
id="path3834"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="M 26.31204,9.2549017 29.307138,8.946193 c 1.930719,-0.2361949 1.627499,7.01011 -0.03235,6.862976 L 26.236601,15.553807 z M 0,0 0,23 c 15.021262,-4.846203 26.918346,-4.787057 43,0 L 43,0 C 26.964088,7.5152881 15.064204,7.6359799 0,0 z m 41.5625,2.59375 0,2.90625 -3.96875,1.46875 0,3.6875 3.40625,-0.0625 0,2.4375 -3.40625,0 0,3.65625 4.15625,1.125 0,2.90625 -6.71875,-1.6875 0,-13.875 z M 1.90625,2.8125 4.59375,4.03125 6.375,14.5625 8.03125,5.3125 10.625,6.125 l 2.34375,8.5 1.5,-7.65625 L 17.0625,7.3125 14.71875,17.75 11.34375,18.21875 9.5,10.3125 l -1.53125,8.53125 -3.5,0.8125 z M 30,6.75 c 4.450278,0.058184 3.725392,11.914384 -0.5625,11.3125 l -5.6875,-0.53125 0.0625,-10.0625 5.75,-0.6875 C 29.716868,6.7577574 29.856443,6.7481231 30,6.75 z m -11.4375,0.71875 2.625,0.09375 0,9.84375 -2.625,0.09375 z"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccsccccsccccc" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -711,8 +711,10 @@ void cView::DoDrawImage(int num, cTemplateFunction *func, int x0, int y0) {
|
|||||||
break; }
|
break; }
|
||||||
case itImage: {
|
case itImage: {
|
||||||
cImageLoader imgLoader;
|
cImageLoader imgLoader;
|
||||||
if (imgLoader.LoadImage(path.c_str(), width, height)) {
|
if (imgLoader.LoadImage(path.c_str())) {
|
||||||
DrawImage(num, pos, imgLoader.GetImage());
|
cImage *image = imgLoader.CreateImage(width, height);
|
||||||
|
DrawImage(num, pos, *image);
|
||||||
|
delete(image);
|
||||||
}
|
}
|
||||||
break; }
|
break; }
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user