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 /libcore | |
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
Diffstat (limited to 'libcore')
-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 |
8 files changed, 470 insertions, 522 deletions
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 - |