Version 0.0.5 - added SVG Support

This commit is contained in:
louis 2014-11-15 11:15:48 +01:00
commit 0ed710a868
21 changed files with 804 additions and 593 deletions

50
HISTORY
View File

@ -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

View File

@ -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 \

71
README
View File

@ -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.

View File

@ -7,7 +7,6 @@ cDesignerConfig::cDesignerConfig() {
skinPathSet = false;
logoPathSet = false;
//Common
logoExtension = "png";
numLogosPerSizeInitial = 30;
limitLogoCache = 1;
numLogosMax = 200;

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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;
bool cImageLoader::LoadImage(const char *path, int width, int height) {
if (cImageMagickWrapper::LoadImage(path)) {
buffer.sample(Geometry(width, height));
return true;
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);
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;
}
}

View File

@ -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>
using namespace Magick;
//
// Image importers
//
class cImageImporter {
public:
cImageImporter() {};
virtual ~cImageImporter() {};
virtual bool LoadImage(const char *path) { return false; };
virtual void DrawToCairo(cairo_t *cr) {};
virtual void GetImageSize(int &width, int &height) {};
};
class cImageLoader : public cImageMagickWrapper {
// Image importer for PNG
class cImageImporterPNG : public cImageImporter {
public:
cImageImporterPNG();
~cImageImporterPNG();
bool LoadImage(const char *path);
void DrawToCairo(cairo_t *cr);
void GetImageSize(int &width, int &height);
private:
cairo_surface_t *surface;
};
// Image importer for SVG
class cImageImporterSVG : public cImageImporter {
public:
cImageImporterSVG();
~cImageImporterSVG();
bool LoadImage(const char *path);
void DrawToCairo(cairo_t *cr);
void GetImageSize(int &width, int &height);
private:
RsvgHandle *handle;
};
// Image importer for JPG
#if BITS_IN_JSAMPLE != 8
#error libjpeg has to be compiled with 8-bit samples!
#endif
class cImageImporterJPG : public cImageImporter {
public:
cImageImporterJPG();
~cImageImporterJPG();
bool LoadImage(const char *path);
void DrawToCairo(cairo_t *cr);
void GetImageSize(int &width, int &height);
private:
j_decompress_ptr cinfo;
FILE *infile;
};
//
// Image loader class
//
class cImageLoader {
private:
cImageImporter *importer;
public:
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

View File

@ -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);
}

View File

@ -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

View File

@ -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++;
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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
#endif //__XMLPARSER_H

View File

@ -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) {

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="49"
height="24"
sodipodi:docname="ico_hd_off.svg">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1769"
inkscape:window-height="1195"
id="namedview4"
showgrid="false"
inkscape:zoom="6.9532167"
inkscape:cx="-12.199961"
inkscape:cy="10.824729"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<path
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196081000000004;opacity:0.4;fill-opacity:1"
d="m 3.7627119,1.5762712 5.8474576,0 -1.220339,6.9661017 9.1525425,-0.050847 0.966102,-7.0677966 6.016389,0.014893 -2.965542,21.1376493 -5.993831,0.06883 1.20853,-8.712893 -9.3502922,0.08899 -1.6652543,8.491525 -5.30084738,0.06356 z"
id="path3759"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078000000000;opacity:0.4"
d="m 28.398305,1.3728813 15.991526,0 C 46.277579,1.243275 49.255354,2.7574438 48.61017,8.0338983 47.616873,15.342244 46.343401,22.177506 41.288136,22.627119 L 24.915254,22.525424 27.20339,8.7966102 l 5.898305,-0.025424 -1.576271,9.5338988 7.677966,0 c 2.596312,0.118399 3.234177,-5.226757 3.457627,-7.90678 0.408058,-3.1501646 0.153706,-4.2577277 -1.420115,-4.3115034 L 27.61017,6.152542 z"
id="path3767"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="49"
height="24"
sodipodi:docname="ico_hd_on.svg">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1769"
inkscape:window-height="1195"
id="namedview4"
showgrid="false"
inkscape:zoom="6.9532167"
inkscape:cx="19.799617"
inkscape:cy="10.824729"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<path
style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196081000000004;opacity:1;fill-opacity:1"
d="m 3.7627119,1.5762712 5.8474576,0 -1.220339,6.9661017 9.1525425,-0.050847 0.966102,-7.0677966 6.016389,0.014893 -2.965542,21.1376493 -5.993831,0.06883 1.20853,-8.712893 -9.3502922,0.08899 -1.6652543,8.491525 -5.30084738,0.06356 z"
id="path3759"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078000000000"
d="m 28.398305,1.3728813 15.991526,0 C 46.277579,1.243275 49.255354,2.7574438 48.61017,8.0338983 47.616873,15.342244 46.343401,22.177506 41.288136,22.627119 L 24.915254,22.525424 27.20339,8.7966102 l 5.898305,-0.025424 -1.576271,9.5338988 7.677966,0 c 2.596312,0.118399 3.234177,-5.226757 3.457627,-7.90678 0.408058,-3.1501646 0.153706,-4.2577277 -1.420115,-4.3115034 L 27.61017,6.152542 z"
id="path3767"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="43"
height="23"
sodipodi:docname="ico_widescreen_off.svg">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2048"
inkscape:window-height="1481"
id="namedview4"
showgrid="false"
inkscape:zoom="16"
inkscape:cx="-4.8693805"
inkscape:cy="19.882154"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path3834"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:0.4"
d="M 26.31204,9.2549017 29.307138,8.946193 c 1.930719,-0.2361949 1.627499,7.01011 -0.03235,6.862976 L 26.236601,15.553807 z M 0,0 0,23 c 15.021262,-4.846203 26.918346,-4.787057 43,0 L 43,0 C 26.964088,7.5152881 15.064204,7.6359799 0,0 z m 41.5625,2.59375 0,2.90625 -3.96875,1.46875 0,3.6875 3.40625,-0.0625 0,2.4375 -3.40625,0 0,3.65625 4.15625,1.125 0,2.90625 -6.71875,-1.6875 0,-13.875 z M 1.90625,2.8125 4.59375,4.03125 6.375,14.5625 8.03125,5.3125 10.625,6.125 l 2.34375,8.5 1.5,-7.65625 L 17.0625,7.3125 14.71875,17.75 11.34375,18.21875 9.5,10.3125 l -1.53125,8.53125 -3.5,0.8125 z M 30,6.75 c 4.450278,0.058184 3.725392,11.914384 -0.5625,11.3125 l -5.6875,-0.53125 0.0625,-10.0625 5.75,-0.6875 C 29.716868,6.7577574 29.856443,6.7481231 30,6.75 z m -11.4375,0.71875 2.625,0.09375 0,9.84375 -2.625,0.09375 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccsccccsccccc" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
width="43"
height="23"
sodipodi:docname="ico_widescreen_on.png">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2048"
inkscape:window-height="1481"
id="namedview4"
showgrid="false"
inkscape:zoom="16"
inkscape:cx="9.0368695"
inkscape:cy="19.882154"
inkscape:window-x="-2"
inkscape:window-y="-3"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path3834"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 26.31204,9.2549017 29.307138,8.946193 c 1.930719,-0.2361949 1.627499,7.01011 -0.03235,6.862976 L 26.236601,15.553807 z M 0,0 0,23 c 15.021262,-4.846203 26.918346,-4.787057 43,0 L 43,0 C 26.964088,7.5152881 15.064204,7.6359799 0,0 z m 41.5625,2.59375 0,2.90625 -3.96875,1.46875 0,3.6875 3.40625,-0.0625 0,2.4375 -3.40625,0 0,3.65625 4.15625,1.125 0,2.90625 -6.71875,-1.6875 0,-13.875 z M 1.90625,2.8125 4.59375,4.03125 6.375,14.5625 8.03125,5.3125 10.625,6.125 l 2.34375,8.5 1.5,-7.65625 L 17.0625,7.3125 14.71875,17.75 11.34375,18.21875 9.5,10.3125 l -1.53125,8.53125 -3.5,0.8125 z M 30,6.75 c 4.450278,0.058184 3.725392,11.914384 -0.5625,11.3125 l -5.6875,-0.53125 0.0625,-10.0625 5.75,-0.6875 C 29.716868,6.7577574 29.856443,6.7481231 30,6.75 z m -11.4375,0.71875 2.625,0.09375 0,9.84375 -2.625,0.09375 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccsccccsccccc" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -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: