diff options
author | louis <louis.braun@gmx.de> | 2014-11-15 11:15:48 +0100 |
---|---|---|
committer | louis <louis.braun@gmx.de> | 2014-11-15 11:15:48 +0100 |
commit | 0ed710a86884136a7bd772322f13f0b176a5dc22 (patch) | |
tree | cd4ae6f14b29988d35ce67acb9012c610348bc95 | |
parent | f225c38103013faf38512cc61362cf9bb9088ba6 (diff) | |
parent | 7a69d868c422218817f1c92a6666ee6c83825d23 (diff) | |
download | vdr-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-- | HISTORY | 50 | ||||
-rw-r--r-- | Makefile | 14 | ||||
-rw-r--r-- | README | 71 | ||||
-rw-r--r-- | config.c | 1 | ||||
-rw-r--r-- | config.h | 1 | ||||
-rw-r--r-- | libcore/imagecache.c | 76 | ||||
-rw-r--r-- | libcore/imagecache.h | 7 | ||||
-rw-r--r-- | libcore/imageloader.c | 392 | ||||
-rw-r--r-- | libcore/imageloader.h | 81 | ||||
-rw-r--r-- | libcore/imagemagickwrapper.c | 162 | ||||
-rw-r--r-- | libcore/imagemagickwrapper.h | 28 | ||||
-rw-r--r-- | libcore/imagescaler.c | 149 | ||||
-rw-r--r-- | libcore/imagescaler.h | 97 | ||||
-rw-r--r-- | libtemplate/xmlparser.c | 10 | ||||
-rw-r--r-- | libtemplate/xmlparser.h | 4 | ||||
-rw-r--r-- | skindesigner.c | 4 | ||||
-rw-r--r-- | skins/metrixhd/themes/default/icons/ico_hd_off.svg | 64 | ||||
-rw-r--r-- | skins/metrixhd/themes/default/icons/ico_hd_on.svg | 64 | ||||
-rw-r--r-- | skins/metrixhd/themes/default/icons/ico_widescreen_off.svg | 58 | ||||
-rw-r--r-- | skins/metrixhd/themes/default/icons/ico_widescreen_on.svg | 58 | ||||
-rw-r--r-- | views/view.c | 6 |
21 files changed, 804 insertions, 593 deletions
@@ -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 @@ -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 \ @@ -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. @@ -7,7 +7,6 @@ cDesignerConfig::cDesignerConfig() { skinPathSet = false; logoPathSet = false; //Common - logoExtension = "png"; numLogosPerSizeInitial = 30; limitLogoCache = 1; numLogosMax = 200; @@ -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:
|