summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlouis <louis.braun@gmx.de>2014-11-15 11:15:48 +0100
committerlouis <louis.braun@gmx.de>2014-11-15 11:15:48 +0100
commit0ed710a86884136a7bd772322f13f0b176a5dc22 (patch)
treecd4ae6f14b29988d35ce67acb9012c610348bc95
parentf225c38103013faf38512cc61362cf9bb9088ba6 (diff)
parent7a69d868c422218817f1c92a6666ee6c83825d23 (diff)
downloadvdr-plugin-skindesigner-0.0.5.tar.gz
vdr-plugin-skindesigner-0.0.5.tar.bz2
Version 0.0.5 - added SVG Support0.0.5
-rw-r--r--HISTORY50
-rw-r--r--Makefile14
-rw-r--r--README71
-rw-r--r--config.c1
-rw-r--r--config.h1
-rw-r--r--libcore/imagecache.c76
-rw-r--r--libcore/imagecache.h7
-rw-r--r--libcore/imageloader.c392
-rw-r--r--libcore/imageloader.h81
-rw-r--r--libcore/imagemagickwrapper.c162
-rw-r--r--libcore/imagemagickwrapper.h28
-rw-r--r--libcore/imagescaler.c149
-rw-r--r--libcore/imagescaler.h97
-rw-r--r--libtemplate/xmlparser.c10
-rw-r--r--libtemplate/xmlparser.h4
-rw-r--r--skindesigner.c4
-rw-r--r--skins/metrixhd/themes/default/icons/ico_hd_off.svg64
-rw-r--r--skins/metrixhd/themes/default/icons/ico_hd_on.svg64
-rw-r--r--skins/metrixhd/themes/default/icons/ico_widescreen_off.svg58
-rw-r--r--skins/metrixhd/themes/default/icons/ico_widescreen_on.svg58
-rw-r--r--views/view.c6
21 files changed, 804 insertions, 593 deletions
diff --git a/HISTORY b/HISTORY
index 7f11470..bafd45c 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7,14 +7,17 @@ VDR Plugin 'skindesigner' Revision History
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 common channel logo path for all skins
- changed skin handling so that every skin is directly shown in VDR OSD Menu
- 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 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
- support for global variables type "double"
- added setup options to configure rerun display behaviour
@@ -23,36 +26,46 @@ Version 0.0.2
- added vps token in menudetailepg
- implemented cSDDisplayMenu::GetTextAreaFont()
- introduced new viewelement audioinfo in displaychannel
-- added setup option to choose Menu Item display method between "at one go" and "after one another"
-- fixed bug that new skin was not properly loaded sometimes when skin was 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 setup option to choose Menu Item display method between "at one go" and
+ "after one another"
+- fixed bug that new skin was not properly loaded sometimes when skin was
+ 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 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
- 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
- using default menu list in case an invalid MenuCategory is set
- added device info in displaychannel, example in metrixHD
- improved menu icon display, additionally using menu cat
- changed devices list, device numbers start with 0
- 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
-- 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
- 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
- in replay exactly hits the mark
-- added {channelname}, {channelid}, {channellogoexists} for all schedules list and current views
+- added "active" Token for cutting marks so that a mark can be displayed in a
+ dedicated way if current position in replay exactly hits the mark
+- added {channelname}, {channelid}, {channellogoexists} for all schedules list
+ and current views
- 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
-- fixed Bug that displaychannel was not shown after closing displaymenu with "backspace" (with active
- menuorg plugin)
+- fixed Bug that displaychannel was not shown after closing displaymenu with
+ "backspace" (with active menuorg plugin)
- fixed Bug with menuselection Patch
- added tokens {month}, {monthname} and {year} in displaymenutimers listitem and currentitem
- 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
+- added SVG Support - thanks to Manuel Reimer!
+
+Version 0.0.5
diff --git a/Makefile b/Makefile
index 620c7fa..dedf333 100644
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,6 @@
#
# $Id$ Makefile 1.0 2014/07/24 louis Exp $
-# External image lib to use: imagemagick, graphicsmagick
-IMAGELIB = imagemagick
-
# Config
CONFIG := #-DDOPROFILE # enable profiling code
@@ -50,13 +47,8 @@ DEFINES += $(shell xml2-config --cflags)
INCLUDES += $(shell pkg-config --cflags freetype2 fontconfig)
-ifeq ($(IMAGELIB), imagemagick)
- INCLUDES += $(shell pkg-config --cflags Magick++)
- LIBS += $(shell pkg-config --libs Magick++)
-else ifeq ($(IMAGELIB), graphicsmagick)
- INCLUDES += $(shell pkg-config --cflags GraphicsMagick++)
- LIBS += $(shell pkg-config --libs GraphicsMagick++)
-endif
+INCLUDES += $(shell pkg-config --cflags librsvg-2.0 cairo-png) -ljpeg
+LIBS += $(shell pkg-config --libs librsvg-2.0 cairo-png) -ljpeg
LIBS += $(shell xml2-config --libs)
@@ -74,8 +66,6 @@ OBJS = $(PLUGIN).o \
libcore/pixmapcontainer.o \
libcore/fontmanager.o \
libcore/imagecache.o \
- libcore/imagemagickwrapper.o \
- libcore/imagescaler.o \
libcore/helpers.o \
libcore/imageloader.o \
libcore/recfolderinfo.o \
diff --git a/README b/README
index 14fcfac..15c1cbd 100644
--- a/README
+++ b/README
@@ -5,7 +5,7 @@ Written by: Louis Braun <louis DOT braun AT gmx DOT de>
Project's homepage: http://projects.vdr-developer.org/projects/plg-skindesigner
Latest version: http://projects.vdr-developer.org/projects/plg-skindesigner/files
-GIT repository: git clone git://projects.vdr-developer.org/vdr-plugin-skindesigner.git
+GIT repository: git clone git://projects.vdr-developer.org/vdr-plugin-skindesigner.git
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,9 +16,9 @@ See the file COPYING for more information.
Description
-----------
-Skindesigner is a VDR skin engine that displays XML based Skins.
+Skindesigner is a VDR skin engine that displays XML based Skins.
-Currently two XML Skins (MetrixHD and nOpacity freestyle) are included in
+Currently two XML Skins (MetrixHD and nOpacity freestyle) are included in
<pluginsourcedir>/skins/
Requirements
@@ -26,19 +26,19 @@ Requirements
- VDR version >= 2.0.0
-- Installed ImageMagick or GraphicsMagick for displaying png/jpg Icons, Channel Logos
- and EPG Images (configurable during make via IMAGELIB = imagemagick|graphicsmagick
- parameter)
+- cairo
+
+- librsvg-2
- 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.
-- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the schedules
- menu with epgsearch
+- epgsearch Git since commit ba7c6277 (2013-01-03) to correctly replace the
+ schedules menu with epgsearch
-Installation
+Installation
------------
After "normal" Plugin installation you have to care about the paths for the
@@ -53,10 +53,10 @@ XML skins and epg images. The following paths can be set at startup:
-e path, --epgimages=path
Path to the epgimages (Default: <CacheDirectory>/epgimages/)
-ResourceDirectory and CacheDirectory are taken from your VDR configuration (make.config
-or vdr.pc).
+ResourceDirectory and CacheDirectory are taken from your VDR configuration
+(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.
For S2-6400 Users: Disable High Level OSD, otherwise the plugin will not be
@@ -67,20 +67,21 @@ an suitable true color OSD.
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
-default, you may want to install this font (included in <SkinSourceDirectory>/fonts/)
-first. Otherwise the inside VDRs OSD menu configured vdrOsd Font is used as default.
+Since the default skin MetrixHD uses VDROpenSans as font which is not installed
+per default, you may want to install this font (included in
+<SkinSourceDirectory>/fonts/) first. Otherwise the inside VDRs OSD menu
+configured vdrOsd Font is used as default.
Channel Logos
-------------
-Since each XML skin is responsible for it's used channel logos, skindesigner searches
-for channel logos only in the skin dependend directory
+Since each XML skin is responsible for it's used channel logos, skindesigner
+searches for channel logos only in the skin dependend directory
<ResourceDirectory>/plugins/skindesigner/skins/<skinname>/logos
-Each copy your used logos directly to this directory or set a symbolic link to a common
-channellogo directory.
+Each copy your used logos directly to this directory or set a symbolic link to
+a common channellogo directory.
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
@@ -89,17 +90,19 @@ git clone https://github.com/3PO/Senderlogos.git logos
An update of the logos can then be done with a "git pull" just inside this
directory.
-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
-appropriate channel logo. With this, approximately 90% of the channel logos should work
-immediately after placing the channel logos in the correct place. So if you have to change
-the name of a channel logo (may be by inserting a space or a hyphen) so that it fits to
-the channel name, only use lower case letters, and not the name of the channel with upper
-and lower letters as displayed inside VDR.
-If no logo is found for the channel name, additionally a search for a logo named as the
-ChannelID is performed. Analog to the channel name the ChannelID is also converted to lower
-case letters. This allows channel logos for channels with changing names (for instance
-Sky Feed Channels).
-Additional hint: some channels have slashes in their name (in germany 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.
+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 appropriate channel logo. With this, approximately 90% of the channel
+logos should work immediately after placing the channel logos in the correct
+place. So if you have to change the name of a channel logo (may be by inserting
+a space or a hyphen) so that it fits to the channel name, only use lower case
+letters, and not the name of the channel with upper and lower letters as
+displayed inside VDR.
+If no logo is found for the channel name, additionally a search for a logo
+named as the ChannelID is performed. Analog to the channel name the ChannelID
+is also converted to lower case letters. This allows channel logos for channels
+with changing names (for instance Sky Feed Channels).
+Additional hint: some channels have slashes in their name (in germany
+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.
diff --git a/config.c b/config.c
index 129cb11..7052f50 100644
--- a/config.c
+++ b/config.c
@@ -7,7 +7,6 @@ cDesignerConfig::cDesignerConfig() {
skinPathSet = false;
logoPathSet = false;
//Common
- logoExtension = "png";
numLogosPerSizeInitial = 30;
limitLogoCache = 1;
numLogosMax = 200;
diff --git a/config.h b/config.h
index 11a5963..3a031c0 100644
--- a/config.h
+++ b/config.h
@@ -48,7 +48,6 @@ public:
void AddPlugin(string name, map < int, string > &menus);
void InitPluginIterator(void);
map <int,string> *GetPluginTemplates(string &name);
- cString logoExtension;
cString skinPath;
cString logoPath;
cString epgImagePath;
diff --git a/libcore/imagecache.c b/libcore/imagecache.c
index 9ad9918..369322e 100644
--- a/libcore/imagecache.c
+++ b/libcore/imagecache.c
@@ -7,14 +7,13 @@
#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() {
+cImageCache::cImageCache() {
tempStaticLogo = NULL;
}
@@ -141,27 +140,19 @@ bool cImageCache::LogoExists(string channelID) {
if (!channel)
return false;
string logoLower = StrToLowerCase(channel->Name());
- string logoExt = *config.logoExtension;
- bool logoExists = FileExists(logoPath.c_str(), logoLower, logoExt);
- if (logoExists) {
- return true;
- }
- logoExists = FileExists(logoPath.c_str(), channelID, logoExt);
- if (logoExists) {
- return true;
- }
- return false;
+
+ return (FileExists(logoPath.c_str(), logoLower, "svg") ||
+ FileExists(logoPath.c_str(), logoLower, "png") ||
+ FileExists(logoPath.c_str(), channelID, "svg") ||
+ FileExists(logoPath.c_str(), channelID, "png"));
}
bool cImageCache::SeparatorLogoExists(string name) {
string separatorPath = *cString::sprintf("%sseparatorlogos/", logoPath.c_str());
string nameLower = StrToLowerCase(name.c_str());
- string logoExt = *config.logoExtension;
- bool logoExists = FileExists(separatorPath, nameLower, logoExt);
- if (logoExists) {
- return true;
- }
- return false;
+
+ return (FileExists(separatorPath, nameLower, "svg") ||
+ FileExists(separatorPath, nameLower, "png"));
}
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 success = false;
cString subdir("");
if (type == itMenuIcon)
subdir = "menuicons";
else if (type == itIcon)
subdir = "icons";
cString subIconPath = cString::sprintf("%s%s/", iconPath.c_str(), *subdir);
- success = LoadImage(name, *subIconPath, "png");
- if (success) {
- return true;
- }
- return false;
+
+ if (FileExists(*subIconPath, name, "svg"))
+ return LoadImage(*subIconPath, name, "svg");
+ else
+ return LoadImage(*subIconPath, name, "png");
}
bool cImageCache::LoadLogo(const cChannel *channel) {
@@ -331,33 +321,33 @@ bool cImageCache::LoadLogo(const cChannel *channel) {
return false;
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
string logoLower = StrToLowerCase(channel->Name());
- bool success = false;
- success = LoadImage(channelID.c_str(), logoPath.c_str(), *config.logoExtension);
- if (success)
- return true;
- success = LoadImage(logoLower.c_str(), logoPath.c_str(), *config.logoExtension);
- if (success)
- return true;
+
+ if (FileExists(logoPath.c_str(), channelID.c_str(), "svg"))
+ return LoadImage(logoPath.c_str(), channelID.c_str(), "svg");
+ if (FileExists(logoPath.c_str(), channelID.c_str(), "png"))
+ return LoadImage(logoPath.c_str(), channelID.c_str(), "png");
+ if (FileExists(logoPath.c_str(), logoLower.c_str(), "svg"))
+ 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;
}
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());
- bool success = false;
- success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
- if (success)
- return true;
- return false;
+ if (FileExists(separatorPath, nameLower.c_str(), "svg"))
+ return LoadImage(separatorPath, nameLower.c_str(), "svg");
+ else
+ return LoadImage(separatorPath, nameLower.c_str(), "png");
}
bool cImageCache::LoadSkinpart(string name) {
- bool success = false;
- success = LoadImage(name, skinPartsPath.c_str(), "png");
- if (success) {
- return true;
- }
- return false;
+ if (FileExists(skinPartsPath.c_str(), name, "svg"))
+ return LoadImage(skinPartsPath.c_str(), name, "svg");
+ else
+ return LoadImage(skinPartsPath.c_str(), name, "png");
}
void cImageCache::Clear(void) {
diff --git a/libcore/imagecache.h b/libcore/imagecache.h
index db56a67..4e88600 100644
--- a/libcore/imagecache.h
+++ b/libcore/imagecache.h
@@ -5,14 +5,11 @@
#include <vdr/osd.h>
#include <vdr/skins.h>
-#include <Magick++.h>
#include <vector>
-#include "imagemagickwrapper.h"
+#include "imageloader.h"
#include "../libtemplate/templatefunction.h"
-using namespace Magick;
-
-class cImageCache : public cImageMagickWrapper {
+class cImageCache : public cImageLoader {
public:
cImageCache();
~cImageCache();
diff --git a/libcore/imageloader.c b/libcore/imageloader.c
index 61e8076..139e2d0 100644
--- a/libcore/imageloader.c
+++ b/libcore/imageloader.c
@@ -1,62 +1,400 @@
#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() {
+ importer = NULL;
}
cImageLoader::~cImageLoader() {
+ delete(importer);
}
-cImage cImageLoader::GetImage() {
- return CreateImageCopy();
-}
+cImage *cImageLoader::CreateImage(int width, int height, bool preserveAspect) {
+ if (!importer)
+ return NULL;
+
+ int w, h;
+ importer->GetImageSize(w, h);
+ if (width == 0)
+ width = w;
+ if (height == 0)
+ height = h;
+
+ cairo_surface_t *surface;
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
-bool cImageLoader::LoadImage(const char *path, int width, int height) {
- if (cImageMagickWrapper::LoadImage(path)) {
- buffer.sample(Geometry(width, height));
- return true;
+ 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) {
cString logoPath;
cString logoPathSkin = cString::sprintf("%s%s/themes/%s/logos/", *config.skinPath, Setup.OSDSkin, Setup.OSDTheme);
- if (FolderExists(*logoPathSkin)) {
+
+ if (FolderExists(*logoPathSkin))
logoPath = logoPathSkin;
- } else {
+ else
logoPath = config.logoPath;
- }
- cString logoExt = config.logoExtension;
+
DIR *folder = NULL;
struct dirent *file;
folder = opendir(logoPath);
- if (!folder) {
+ if (!folder)
return;
- }
- while (file = readdir(folder)) {
- if (endswith(file->d_name, *logoExt)) {
+
+ while ( (file = readdir(folder)) ) {
+ if (endswith(file->d_name, ".png") ||
+ endswith(file->d_name, ".svg")) {
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 (LoadImage(filePath.str().c_str())) {
+ int logoWidth = 0;
+ int logoHeight = 0;
+ importer->GetImageSize(logoWidth, logoHeight);
if (logoWidth > 0 && logoHeight > 0) {
width = logoWidth;
height = logoHeight;
+ delete(importer);
+ importer = NULL;
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;
}
}
diff --git a/libcore/imageloader.h b/libcore/imageloader.h
index 2a148be..a06f433 100644
--- a/libcore/imageloader.h
+++ b/libcore/imageloader.h
@@ -1,23 +1,82 @@
#ifndef __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/skins.h>
-#include <Magick++.h>
-#include "imagemagickwrapper.h"
+#include <vdr/tools.h>
+
+//
+// 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) {};
+};
+
+// 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;
+};
-using namespace Magick;
+// Image importer for JPG
+#if BITS_IN_JSAMPLE != 8
+ #error libjpeg has to be compiled with 8-bit samples!
+#endif
-class cImageLoader : public cImageMagickWrapper {
+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:
cImageLoader();
- ~cImageLoader();
- cImage GetImage();
- bool LoadImage(const char *path, int width, int height);
+ virtual ~cImageLoader();
+ cImage *CreateImage(int width, int height, bool preserveAspect = true);
+ bool LoadImage(std::string Path, std::string FileName, std::string Extension);
+ bool LoadImage(const char *fullpath);
void DeterminateChannelLogoSize(int &width, int &height);
-private:
};
#endif //__NOPACITY_IMAGELOADER_H
diff --git a/libcore/imagemagickwrapper.c b/libcore/imagemagickwrapper.c
deleted file mode 100644
index ab1bcba..0000000
--- a/libcore/imagemagickwrapper.c
+++ /dev/null
@@ -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);
-}
diff --git a/libcore/imagemagickwrapper.h b/libcore/imagemagickwrapper.h
deleted file mode 100644
index 5f9901e..0000000
--- a/libcore/imagemagickwrapper.h
+++ /dev/null
@@ -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
diff --git a/libcore/imagescaler.c b/libcore/imagescaler.c
deleted file mode 100644
index 64fe3dc..0000000
--- a/libcore/imagescaler.c
+++ /dev/null
@@ -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++;
- }
-}
diff --git a/libcore/imagescaler.h b/libcore/imagescaler.h
deleted file mode 100644
index 1182811..0000000
--- a/libcore/imagescaler.h
+++ /dev/null
@@ -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
-
diff --git a/libtemplate/xmlparser.c b/libtemplate/xmlparser.c
index 4b8e85a..0fede38 100644
--- a/libtemplate/xmlparser.c
+++ b/libtemplate/xmlparser.c
@@ -13,7 +13,6 @@ cXmlParser::cXmlParser(void) {
root = NULL;
ctxt = NULL;
- xmlInitParser();
initGenericErrorDefaultFunc(NULL);
xmlSetStructuredErrorFunc(NULL, SkinDesignerXMLErrorHandler);
ctxt = xmlNewParserCtxt();
@@ -22,7 +21,6 @@ cXmlParser::cXmlParser(void) {
cXmlParser::~cXmlParser() {
DeleteDocument();
xmlFreeParserCtxt(ctxt);
- xmlCleanupParser();
}
/*********************************************************************
@@ -801,3 +799,11 @@ bool cXmlParser::DebugViewElement(xmlNodePtr node) {
}
return false;
}
+
+void cXmlParser::InitLibXML() {
+ xmlInitParser();
+}
+
+void cXmlParser::CleanupLibXML() {
+ xmlCleanupParser();
+}
diff --git a/libtemplate/xmlparser.h b/libtemplate/xmlparser.h
index 3156042..18476e9 100644
--- a/libtemplate/xmlparser.h
+++ b/libtemplate/xmlparser.h
@@ -53,6 +53,8 @@ public:
bool ParsePluginView(string plugName, int templateNumber);
bool ParseGlobals(void);
void DeleteDocument(void);
+ static void InitLibXML();
+ static void CleanupLibXML();
};
-#endif //__XMLPARSER_H \ No newline at end of file
+#endif //__XMLPARSER_H
diff --git a/skindesigner.c b/skindesigner.c
index 47e31ed..ed7e181 100644
--- a/skindesigner.c
+++ b/skindesigner.c
@@ -19,7 +19,7 @@
#endif
-static const char *VERSION = "0.0.4";
+static const char *VERSION = "0.0.5";
static const char *DESCRIPTION = "SkinDesigner";
static const char *MAINMENUENTRY = "Skin Designer";
@@ -95,6 +95,7 @@ bool cPluginSkinDesigner::Initialize(void) {
}
bool cPluginSkinDesigner::Start(void) {
+ cXmlParser::InitLibXML();
bool trueColorAvailable = true;
if (!cOsdProvider::SupportsTrueColor()) {
esyslog("skindesigner: No TrueColor OSD found! Using default Skin LCARS!");
@@ -121,6 +122,7 @@ bool cPluginSkinDesigner::Start(void) {
void cPluginSkinDesigner::Stop(void) {
delete imgCache;
delete fontManager;
+ cXmlParser::CleanupLibXML();
}
void cPluginSkinDesigner::Housekeeping(void) {
diff --git a/skins/metrixhd/themes/default/icons/ico_hd_off.svg b/skins/metrixhd/themes/default/icons/ico_hd_off.svg
new file mode 100644
index 0000000..897bdfc
--- /dev/null
+++ b/skins/metrixhd/themes/default/icons/ico_hd_off.svg
@@ -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>
diff --git a/skins/metrixhd/themes/default/icons/ico_hd_on.svg b/skins/metrixhd/themes/default/icons/ico_hd_on.svg
new file mode 100644
index 0000000..9c69401
--- /dev/null
+++ b/skins/metrixhd/themes/default/icons/ico_hd_on.svg
@@ -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>
diff --git a/skins/metrixhd/themes/default/icons/ico_widescreen_off.svg b/skins/metrixhd/themes/default/icons/ico_widescreen_off.svg
new file mode 100644
index 0000000..dd91dad
--- /dev/null
+++ b/skins/metrixhd/themes/default/icons/ico_widescreen_off.svg
@@ -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>
diff --git a/skins/metrixhd/themes/default/icons/ico_widescreen_on.svg b/skins/metrixhd/themes/default/icons/ico_widescreen_on.svg
new file mode 100644
index 0000000..e6a91e5
--- /dev/null
+++ b/skins/metrixhd/themes/default/icons/ico_widescreen_on.svg
@@ -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>
diff --git a/views/view.c b/views/view.c
index 75a24e0..864eb45 100644
--- a/views/view.c
+++ b/views/view.c
@@ -711,8 +711,10 @@ void cView::DoDrawImage(int num, cTemplateFunction *func, int x0, int y0) {
break; }
case itImage: {
cImageLoader imgLoader;
- if (imgLoader.LoadImage(path.c_str(), width, height)) {
- DrawImage(num, pos, imgLoader.GetImage());
+ if (imgLoader.LoadImage(path.c_str())) {
+ cImage *image = imgLoader.CreateImage(width, height);
+ DrawImage(num, pos, *image);
+ delete(image);
}
break; }
default: