diff options
author | mrwastl <mrwastl@users.sourceforge.net> | 2011-10-24 20:00:59 +0200 |
---|---|---|
committer | mrwastl <mrwastl@users.sourceforge.net> | 2011-10-24 20:00:59 +0200 |
commit | b560da0e0e08d791bbc404da19c394657af816ac (patch) | |
tree | e00bd6101f197e61eb62b95ff1c4746386fb33bd | |
parent | d14d492732a84e1bda42b0a4a249c83a7d99b93c (diff) | |
download | graphlcd-base-b560da0e0e08d791bbc404da19c394657af816ac.tar.gz graphlcd-base-b560da0e0e08d791bbc404da19c394657af816ac.tar.bz2 |
cImageFile: scaling support for non-ImageMagick files (-> pbm, glcd); serdisp.[ch]: paranoia checks (SetBrightness()!), encapsulation of touch events; cImageCache: syslog message after successful loading of an image; cSkinObject: beauty fix
-rw-r--r-- | glcddrivers/serdisp.c | 44 | ||||
-rw-r--r-- | glcddrivers/serdisp.h | 11 | ||||
-rw-r--r-- | glcdgraphics/extformats.h | 1 | ||||
-rw-r--r-- | glcdgraphics/imagefile.c | 129 | ||||
-rw-r--r-- | glcdgraphics/imagefile.h | 13 | ||||
-rw-r--r-- | glcdskin/cache.c | 3 | ||||
-rw-r--r-- | glcdskin/function.c | 2 | ||||
-rw-r--r-- | glcdskin/object.c | 4 |
8 files changed, 182 insertions, 25 deletions
diff --git a/glcddrivers/serdisp.c b/glcddrivers/serdisp.c index e9e15c4..f6863c7 100644 --- a/glcddrivers/serdisp.c +++ b/glcddrivers/serdisp.c @@ -22,6 +22,8 @@ // for memcpy #include <string.h> +#include <map> + #define SERDISP_VERSION(a,b) ((long)(((a) << 8) + (b))) #define SERDISP_VERSION_GET_MAJOR(_c) ((int)( (_c) >> 8 )) #define SERDISP_VERSION_GET_MINOR(_c) ((int)( (_c) & 0xFF )) @@ -40,15 +42,13 @@ namespace GLCD static void wrapEventListener(void* dd, SDGP_event_t* recylce); -static int simpleTouchX=0, simpleTouchY=0, simpleTouchT=0; -static bool simpleTouchChanged=false; +static std::map<void* ,tTouchEvent*> touchEvents; cDriverSerDisp::cDriverSerDisp(cDriverConfig * config) : cDriver(config) { dd = (void *) NULL; - simpleTouchChanged = false; } int cDriverSerDisp::Init(void) @@ -335,6 +335,10 @@ int cDriverSerDisp::Init(void) // clear display Clear(); + touchEvent = new tTouchEvent; + touchEvent->simpleTouchChanged = false; + touchEvents[dd] = touchEvent; + syslog(LOG_INFO, "%s: SerDisp with %s initialized.\n", config->name.c_str(), controller.c_str()); return 0; } @@ -344,6 +348,10 @@ int cDriverSerDisp::DeInit(void) if (!dd) return 0; + touchEvents.erase(dd); + delete touchEvent; + touchEvent = NULL; + //fp_serdisp_quit(dd); /* use serdisp_close instead of serdisp_quit so that showpic and showtext are usable together with serdisplib */ fp_serdisp_close(dd); @@ -502,12 +510,12 @@ void cDriverSerDisp::Refresh(bool refreshAll) void cDriverSerDisp::SetBrightness(unsigned int percent) { - if ( supports_options && (fp_serdisp_isoption(dd, "BRIGHTNESS") == 1) ) /* if == 1: option is existing AND r/w */ + if ( dd && supports_options && (fp_serdisp_isoption(dd, "BRIGHTNESS") == 1) ) /* if == 1: option is existing AND r/w */ fp_serdisp_setoption(dd, "BRIGHTNESS", (long)percent); } uint32_t cDriverSerDisp::GetDefaultBackgroundColor(void) { - if ( supports_options && fp_serdisp_isoption(dd, "SELFEMITTING") && (fp_serdisp_getoption(dd, "SELFEMITTING", 0)) ) { + if ( dd && supports_options && fp_serdisp_isoption(dd, "SELFEMITTING") && (fp_serdisp_getoption(dd, "SELFEMITTING", 0)) ) { return GRAPHLCD_Black; } return GRAPHLCD_White; @@ -516,7 +524,7 @@ uint32_t cDriverSerDisp::GetDefaultBackgroundColor(void) { bool cDriverSerDisp::SetFeature (const std::string & Feature, int value) { - if (strcasecmp(Feature.c_str(), "TOUCHSCREEN") == 0 || strcasecmp(Feature.c_str(), "TOUCH") == 0) { + if (dd && (strcasecmp(Feature.c_str(), "TOUCHSCREEN") == 0 || strcasecmp(Feature.c_str(), "TOUCH") == 0)) { if (fp_SDGPI_search && fp_SDGPI_isenabled && fp_SDGPI_enable) { uint8_t gpid = fp_SDGPI_search(dd, Feature.c_str()); if (gpid == 0xFF) @@ -566,15 +574,17 @@ bool cDriverSerDisp::GetDriverFeature (const std::string & Feature, int & value } cGLCDEvent * cDriverSerDisp::GetEvent(void) { - if (GLCD::simpleTouchChanged == false) + tTouchEvent* tev = touchEvents[dd]; + if (tev && tev->simpleTouchChanged == false) return NULL; cSimpleTouchEvent * ev = new cSimpleTouchEvent(); - ev->x = simpleTouchX; - ev->y = simpleTouchY; - ev->touch = simpleTouchT; - simpleTouchChanged = false; + ev->x = tev->simpleTouchX; + ev->y = tev->simpleTouchY; + ev->touch = tev->simpleTouchT; + tev->simpleTouchChanged = false; + return ev; } @@ -583,10 +593,14 @@ static void wrapEventListener(void* dd, SDGP_event_t* event) { if (event->type == SDGPT_SIMPLETOUCH) { SDGP_evpkt_simpletouch_t simpletouch; memcpy(&simpletouch, &event->data, sizeof(SDGP_evpkt_simpletouch_t)); - simpleTouchChanged = true; - simpleTouchX = simpletouch.norm_x; - simpleTouchY = simpletouch.norm_y; - simpleTouchT = simpletouch.norm_touch; + + tTouchEvent* tev = touchEvents[dd]; + if (tev) { + tev->simpleTouchChanged = true; + tev->simpleTouchX = simpletouch.norm_x; + tev->simpleTouchY = simpletouch.norm_y; + tev->simpleTouchT = simpletouch.norm_touch; + } } } diff --git a/glcddrivers/serdisp.h b/glcddrivers/serdisp.h index ea1be90..e8cd277 100644 --- a/glcddrivers/serdisp.h +++ b/glcddrivers/serdisp.h @@ -51,6 +51,15 @@ typedef struct SDGP_evpkt_simpletouch_s { /* 16 bytes */ int16_t norm_touch; /* normalised touch value */ } SDGP_evpkt_simpletouch_t; + +typedef struct { + bool simpleTouchChanged; + int simpleTouchX; + int simpleTouchY; + int simpleTouchT; +} tTouchEvent; + + typedef void (*fp_eventlistener_t) (void* dd, SDGP_event_t* recylce); class cDriverConfig; @@ -94,6 +103,8 @@ private: int CheckSetup(); void eventListener (void* dd, SDGP_event_t* recycle); + + tTouchEvent* touchEvent; protected: virtual bool GetDriverFeature (const std::string & Feature, int & value); diff --git a/glcdgraphics/extformats.h b/glcdgraphics/extformats.h index 2f6b2bc..b910c3c 100644 --- a/glcdgraphics/extformats.h +++ b/glcdgraphics/extformats.h @@ -29,7 +29,6 @@ public: virtual bool Load(cImage & image, const std::string & fileName); virtual bool Save(cImage & image, const std::string & fileName); - virtual bool SupportsScaling(void) { return true; } virtual bool LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh); }; diff --git a/glcdgraphics/imagefile.c b/glcdgraphics/imagefile.c index 2f56f4a..d6baf24 100644 --- a/glcdgraphics/imagefile.c +++ b/glcdgraphics/imagefile.c @@ -11,6 +11,7 @@ #include "image.h" #include "imagefile.h" +#include "bitmap.h" namespace GLCD { @@ -32,4 +33,132 @@ bool cImageFile::Save(cImage & image, const std::string & fileName) return false; } + +uint32_t cImageFile::Blend(uint32_t FgColour, uint32_t BgColour, uint8_t Level, double antiAliasGranularity) const +{ + if (antiAliasGranularity > 0.0) + Level = uint8_t(int(Level / antiAliasGranularity + 0.5) * antiAliasGranularity); + int Af = (FgColour & 0xFF000000) >> 24; + int Rf = (FgColour & 0x00FF0000) >> 16; + int Gf = (FgColour & 0x0000FF00) >> 8; + int Bf = (FgColour & 0x000000FF); + int Ab = (BgColour & 0xFF000000) >> 24; + int Rb = (BgColour & 0x00FF0000) >> 16; + int Gb = (BgColour & 0x0000FF00) >> 8; + int Bb = (BgColour & 0x000000FF); + int A = (Ab + (Af - Ab) * Level / 0xFF) & 0xFF; + int R = (Rb + (Rf - Rb) * Level / 0xFF) & 0xFF; + int G = (Gb + (Gf - Gb) * Level / 0xFF) & 0xFF; + int B = (Bb + (Bf - Bb) * Level / 0xFF) & 0xFF; + return (A << 24) | (R << 16) | (G << 8) | B; +} + +bool cImageFile::Scale(cImage & image, uint16_t scalew, uint16_t scaleh, bool AntiAlias) +{ + if (! (scalew || scaleh) ) + return false; + + // one out of scalew/h == 0 ? -> auto aspect ratio + if (scalew && ! scaleh) { + scaleh = (uint16_t)( ((uint32_t)scalew * (uint32_t)image.Height()) / (uint32_t)image.Width() ); + } else if (!scalew && scaleh) { + scalew = (uint16_t)( ((uint32_t)scaleh * (uint32_t)image.Width()) / (uint32_t)image.Height() ); + } + + cImage tempImg = cImage(); + tempImg.SetWidth(scalew); + tempImg.SetHeight(scaleh); + + // Scaling/Blending based on VDR / osd.c + // Fixed point scaling code based on www.inversereality.org/files/bitmapscaling.pdf + // by deltener@mindtremors.com + // + // slightly improved by Wolfgang Astleitner (modify factors and ratios so that scaled image is centered when upscaling) + + double FactorX, FactorY; + int RatioX, RatioY; + + if (!AntiAlias) { + FactorX = (double)scalew / (double)image.Width(); + FactorY = (double)scaleh / (double)image.Height(); + RatioX = (image.Width() << 16) / scalew; + RatioY = (image.Height() << 16) / scaleh; + } else { + FactorX = (double)scalew / (double)(image.Width()-1); + FactorY = (double)scaleh / (double)(image.Height()-1); + RatioX = ((image.Width()-1) << 16) / scalew; + RatioY = ((image.Height()-1) << 16) / scaleh; + } + + bool downscale = (!AntiAlias || (FactorX <= 1.0 && FactorY <= 1.0)); + + for (unsigned int frame = 0; frame < image.Count() ; frame ++ ) { + cBitmap *b = new cBitmap(scalew, scaleh, GRAPHLCD_Transparent); + + cBitmap *currFrame = image.GetBitmap(frame); + + if (downscale) { + // Downscaling - no anti-aliasing: + const uint32_t *DestRow = b->Data(); + int SourceY = 0; + for (int y = 0; y < scaleh; y++) { + int SourceX = 0; + const uint32_t *SourceRow = currFrame->Data() + (SourceY >> 16) * image.Width(); + uint32_t *Dest = (uint32_t*) DestRow; + for (int x = 0; x < scalew; x++) { + *Dest++ = SourceRow[SourceX >> 16]; + SourceX += RatioX; + } + SourceY += RatioY; + DestRow += scalew; + } + } else { + // Upscaling - anti-aliasing: + int SourceY = 0; + for (int y = 0; y < scaleh /*- 1*/; y++) { + int SourceX = 0; + int sy = SourceY >> 16; + uint8_t BlendY = 0xFF - ((SourceY >> 8) & 0xFF); + for (int x = 0; x < scalew /*- 1*/; x++) { + int sx = SourceX >> 16; + uint8_t BlendX = 0xFF - ((SourceX >> 8) & 0xFF); + // TODO: antiAliasGranularity + uint32_t c1 = Blend(currFrame->GetPixel(sx, sy), currFrame->GetPixel(sx + 1, sy), BlendX); + uint32_t c2 = Blend(currFrame->GetPixel(sx, sy + 1), currFrame->GetPixel(sx + 1, sy + 1), BlendX); + uint32_t c3 = Blend(c1, c2, BlendY); + b->DrawPixel(x, y, c3); + SourceX += RatioX; + } + SourceY += RatioY; + } + } + tempImg.AddBitmap(b); + } + // clear all bitmaps from image + image.Clear(); + // set new resolution + image.SetWidth(scalew); + image.SetHeight(scaleh); + // re-add bitmaps from scaled image container + for (unsigned int frame = 0; frame < tempImg.Count(); frame ++) { + image.AddBitmap(new cBitmap(scalew, scaleh, (uint32_t*)tempImg.GetBitmap(frame)->Data())); + } + return true; +} + +bool cImageFile::LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh) +{ + if (Load(image, fileName)) { + if (scalew || scaleh) { + return Scale(image, scalew, scaleh, true); + } else { + return true; + } + } else { + scalew = 0; + scaleh = 0; + return false; + } +} + } // end of namespace diff --git a/glcdgraphics/imagefile.h b/glcdgraphics/imagefile.h index bc7e835..2cc1eba 100644 --- a/glcdgraphics/imagefile.h +++ b/glcdgraphics/imagefile.h @@ -21,18 +21,19 @@ class cImage; class cImageFile { +private: + uint32_t Blend(uint32_t fgcol, uint32_t bgcol, uint8_t level, double antiAliasGranularity = 0.0) const; +protected: + bool Scale(cImage & image, uint16_t scalew, uint16_t scaleh, bool AntiAlias = false); public: cImageFile(); virtual ~cImageFile(); virtual bool Load(cImage & image, const std::string & fileName); virtual bool Save(cImage & image, const std::string & fileName); - virtual bool SupportsScaling(void) { return false; } - virtual bool LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh) { - scalew = 0; - scaleh = 0; - return Load(image, fileName); - } + virtual bool SupportsScaling(void) { return true; } + + virtual bool LoadScaled(cImage & image, const std::string & fileName, uint16_t & scalew, uint16_t & scaleh); }; } // end of namespace diff --git a/glcdskin/cache.c b/glcdskin/cache.c index a0b2929..f0543d9 100644 --- a/glcdskin/cache.c +++ b/glcdskin/cache.c @@ -17,6 +17,8 @@ #include <stdlib.h> #include <string.h> +#include <syslog.h> + #include "cache.h" #include "skin.h" @@ -102,6 +104,7 @@ cImage * cImageCache::Get(const std::string & path, uint16_t & scalew, uint16_t item = LoadImage(path, scalew, scaleh); if (item) { + syslog(LOG_INFO, "INFO: graphlcd: successfully loaded image '%s'\n", path.c_str()); if (images.size() == size) { images.erase(oldest); diff --git a/glcdskin/function.c b/glcdskin/function.c index 6d96c57..2593f70 100644 --- a/glcdskin/function.c +++ b/glcdskin/function.c @@ -176,7 +176,7 @@ bool cSkinFunction::Parse(const std::string & Text) { if (inExpr == 0) { - syslog(LOG_ERR, "ERROR: Unmatched '%c' in expression", *ptr); + syslog(LOG_ERR, "ERROR: Unmatched '%c' in expression (%s)", *ptr, Text.c_str()); return false; } diff --git a/glcdskin/object.c b/glcdskin/object.c index 7e99092..204b0d4 100644 --- a/glcdskin/object.c +++ b/glcdskin/object.c @@ -484,9 +484,9 @@ void cSkinObject::Render(GLCD::cBitmap * screen) uint16_t xoff = 0; uint16_t yoff = 0; if (scalew || scaleh) { - if (image->Width() < Size().w) { + if (image->Width() < (uint16_t)Size().w) { xoff = (Size().w - image->Width() ) / 2; - } else if (image->Height() < Size().h) { + } else if (image->Height() < (uint16_t)Size().h) { yoff = (Size().h - image->Height() ) / 2; } } |