diff options
author | lordjaxom <lordjaxom> | 2004-12-12 19:53:30 +0000 |
---|---|---|
committer | lordjaxom <lordjaxom> | 2004-12-12 19:53:30 +0000 |
commit | 3b0999969632e2820b846ca8adcef6b346ff7441 (patch) | |
tree | 1582ed7db886839ea06c226e228eade0516f60c2 | |
parent | e4c359b5c303cecfc49fb82799805da9fee8dadb (diff) | |
download | vdr-plugin-text2skin-3b0999969632e2820b846ca8adcef6b346ff7441.tar.gz vdr-plugin-text2skin-3b0999969632e2820b846ca8adcef6b346ff7441.tar.bz2 |
1.0-pre3v1.0-pre3
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | bitmap.c | 48 | ||||
-rw-r--r-- | bitmap.h | 6 | ||||
-rw-r--r-- | cache.c | 4 | ||||
-rw-r--r-- | cache.h | 5 | ||||
-rw-r--r-- | display.c | 41 | ||||
-rw-r--r-- | display.h | 13 | ||||
-rw-r--r-- | loader.c | 11 | ||||
-rw-r--r-- | quantize.c | 415 | ||||
-rw-r--r-- | quantize.h | 71 | ||||
-rw-r--r-- | render.c | 28 | ||||
-rw-r--r-- | render.h | 25 | ||||
-rw-r--r-- | text2skin.c | 4 | ||||
-rw-r--r-- | xml/function.c | 23 | ||||
-rw-r--r-- | xml/function.h | 4 | ||||
-rw-r--r-- | xml/parser.c | 61 | ||||
-rw-r--r-- | xml/string.c | 1 | ||||
-rw-r--r-- | xml/type.c | 5 | ||||
-rw-r--r-- | xml/type.h | 2 | ||||
-rw-r--r-- | xml/xml.c | 32 |
20 files changed, 683 insertions, 122 deletions
@@ -55,7 +55,7 @@ PACKAGE = vdr-$(ARCHIVE) OBJS = $(PLUGIN).o loader.o display.o render.o common.o bitmap.o \ file.o i18n.o theme.o cache.o setup.o status.o scroller.o screen.o \ - menu.o font.o \ + menu.o font.o quantize.o \ \ xml/skin.o xml/parser.o xml/string.o xml/object.o xml/function.o \ xml/type.o xml/display.o xml/xml.o @@ -86,13 +86,13 @@ ifdef HAVE_FREETYPE endif ifdef DEBUG - CXXFLAGS += -O2 -g + CXXFLAGS += -g -fno-inline DEFINES += -DDEBUG else CXXFLAGS += -O2 endif -INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include -I. +INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/linux/include -I$(DVBDIR)/include -I. DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' @@ -3,6 +3,7 @@ */ #include "bitmap.h" +#include "quantize.h" #include "setup.h" #include <vdr/tools.h> #define X_DISPLAY_MISSING @@ -16,7 +17,7 @@ using namespace Magick; cText2SkinCache cText2SkinBitmap::mCache(Text2SkinSetup.MaxCacheFill); -cText2SkinBitmap *cText2SkinBitmap::Load(const std::string &Filename, int Alpha) { +cText2SkinBitmap *cText2SkinBitmap::Load(const std::string &Filename, int Alpha, int height, int width, int colors) { if (mCache.Contains(Filename)) return mCache[Filename]; else { @@ -28,10 +29,10 @@ cText2SkinBitmap *cText2SkinBitmap::Load(const std::string &Filename, int Alpha) result = bmp->LoadXpm(Filename.c_str()); else { #ifdef HAVE_IMLIB2 - result = bmp->LoadImlib(Filename.c_str()); + result = bmp->LoadImlib(Filename.c_str(),height,width,colors); #else # ifdef HAVE_IMAGEMAGICK - result = bmp->LoadMagick(Filename.c_str()); + result = bmp->LoadMagick(Filename.c_str(),height,width,colors); # else esyslog("ERROR: text2skin: unknown file format for %s", Filename); # endif @@ -109,34 +110,52 @@ bool cText2SkinBitmap::LoadXpm(const char *Filename) { } #ifdef HAVE_IMLIB2 -bool cText2SkinBitmap::LoadImlib(const char *Filename) { +bool cText2SkinBitmap::LoadImlib(const char *Filename, int height, int width, int colors) { Imlib_Image image; + unsigned char * outputImage = NULL; + unsigned int * outputPalette = NULL; + cQuantizeWu* quantizer = new cQuantizeWu(); cBitmap *bmp = NULL; image = imlib_load_image(Filename); if (!image) return false; Imlib_Context ctx = imlib_context_new(); imlib_context_push(ctx); + if (height != 0 || width != 0){ + imlib_context_set_image(image); + image = imlib_create_cropped_scaled_image(0,0,imlib_image_get_width(), imlib_image_get_height() ,width , height); + } imlib_context_set_image(image); bmp = new cBitmap(imlib_image_get_width(), imlib_image_get_height(), 8); uint8_t *data = (uint8_t*)imlib_image_get_data_for_reading_only(); - int pal = 0, pos = 0; + if ( colors != 0 ){ + quantizer->Quantize(data, imlib_image_get_width()* imlib_image_get_height(), colors); + outputImage = quantizer->OutputImage(); + outputPalette = quantizer->OutputPalette(); + } + int pos = 0; for (int y = 0; y < bmp->Height(); ++y) { for (int x = 0; x < bmp->Width(); ++x) { - tColor col = (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos + 0]; - bmp->DrawPixel(x, y, col); - pos += 4; + if ( colors != 0 ){ + bmp->DrawPixel(x, y , outputPalette[outputImage[y * bmp->Width() + x]] | 0xFF000000 ); + }else{ + tColor col = (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos + 0]; + bmp->DrawPixel(x, y, col); + pos += 4; + } } } + imlib_free_image(); imlib_context_free(ctx); mBitmaps.push_back(bmp); + delete(quantizer); return true; } #endif #ifdef HAVE_IMAGEMAGICK -bool cText2SkinBitmap::LoadMagick(const char *Filename) { +bool cText2SkinBitmap::LoadMagick(const char *Filename, int height, int width, int colors) { std::vector<Image> images; cBitmap *bmp = NULL; try { @@ -149,6 +168,15 @@ bool cText2SkinBitmap::LoadMagick(const char *Filename) { } mDelay = images[0].animationDelay() * 10; for (it = images.begin(); it != images.end(); ++it) { + if (colors != 0){ + (*it).opacity(OpaqueOpacity); + (*it).backgroundColor( Color ( 0,0,0,0) ); + (*it).quantizeColorSpace( RGBColorspace ); + (*it).quantizeColors( colors ); + (*it).quantize(); + } + if (height != 0 || width != 0) + (*it).sample(Geometry(width,height)); w = (*it).columns(); h = (*it).rows(); if ((*it).depth() > 8) { @@ -156,7 +184,7 @@ bool cText2SkinBitmap::LoadMagick(const char *Filename) { return false; } bmp = new cBitmap(w, h, (*it).depth()); - Dprintf("this image has %d colors\n", (*it).totalColors()); + //Dprintf("this image has %d colors\n", (*it).totalColors()); const PixelPacket *pix = (*it).getConstPixels(0, 0, w, h); for (int iy = 0; iy < h; ++iy) { @@ -22,7 +22,7 @@ private: cText2SkinBitmap(void); public: - static cText2SkinBitmap *Load(const std::string &Filename, int Alpha = 0); + static cText2SkinBitmap *Load(const std::string &Filename, int Alpha = 0, int height = 0, int width = 0, int colors = 0); static void ResetCache(void) { mCache.Reset(); } static void FlushCache(void) { mCache.Flush(); } @@ -35,10 +35,10 @@ public: bool LoadXpm(const char *Filename); #ifdef HAVE_IMLIB2 - bool LoadImlib(const char *Filename); + bool LoadImlib(const char *Filename,int height = 0, int width = 0, int colors = 0); #endif #ifdef HAVE_IMAGEMAGICK - bool LoadMagick(const char *Filename); + bool LoadMagick(const char *Filename,int height = 0, int width = 0, int colors = 0); #endif }; @@ -1,5 +1,5 @@ /* - * $Id: cache.c,v 1.2 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: cache.c,v 1.2 2004/06/18 16:08:11 lordjaxom Exp $ */ #include "cache.h" @@ -13,7 +13,7 @@ cText2SkinCache::~cText2SkinCache() { Flush(); } -void cText2SkinCache::Delete(const key_type &/*Key*/, data_type &Data) { +void cText2SkinCache::Delete(const key_type &Key, data_type &Data) { delete Data; } @@ -1,14 +1,15 @@ /* - * $Id: cache.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $ + * $Id: cache.h,v 1.5 2004/06/18 16:08:11 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_CACHE_HPP #define VDR_TEXT2SKIN_CACHE_HPP #include "common.h" +#include <vdr/tools.h> #include <map> #include <vector> -#include <vdr/tools.h> +#include <string> class cText2SkinBitmap; @@ -1,5 +1,5 @@ /* - * $Id: display.c,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: display.c,v 1.6 2004/12/10 21:46:46 lordjaxom Exp $ */ #include "render.h" @@ -23,6 +23,7 @@ cText2SkinDisplayChannel::cText2SkinDisplayChannel(cText2SkinLoader *Loader, boo } cText2SkinDisplayChannel::~cText2SkinDisplayChannel() { + Dprintf("~cTe...\n"); } void cText2SkinDisplayChannel::SetChannel(const cChannel *Channel, int Number) { @@ -50,6 +51,10 @@ void cText2SkinDisplayChannel::SetMessage(eMessageType Type, const char *Text) { SetDirty(); } } + +void cText2SkinDisplayChannel::SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue) { + Dprintf("SetButtons(%s, %s, %s, %s)\n", Red, Green, Yellow, Blue); +} void cText2SkinDisplayChannel::Flush(void) { cText2SkinRender::Flush(); @@ -100,7 +105,7 @@ cxType cText2SkinDisplayChannel::GetTokenData(const txToken &Token) { case tPresentDuration: return mPresent != NULL ? (cxType)TimeType(mPresent->Duration(), Token.Attrib) - : (cxType)false; + : (cxType)false; case tPresentTitle: return mPresent != NULL @@ -535,6 +540,7 @@ cText2SkinDisplayMenu::~cText2SkinDisplayMenu() { void cText2SkinDisplayMenu::Clear(void) { mItems.clear(); + mCurrentItem = (uint)-1; mEvent = NULL; mRecording = NULL; mText = ""; @@ -576,32 +582,35 @@ void cText2SkinDisplayMenu::SetMessage(eMessageType Type, const char *Text) { void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, bool Selectable) { if (Text == NULL) return; + Dprintf("SetItem(%s)\n", Text); - tListItem item; - item.text = Text; - item.sel = Selectable; + tListItem *item = new tListItem(Text, Selectable); + //item.text = Text; + //item.sel = Selectable; for (int i = 0; i < MaxTabs; ++i) { const char *tab = GetTabbedText(Text, i); if (tab) - item.tabs[i] = tab; + item->tabs[i] = tab; if (!Tab(i + 1)) break; } if (mItems.size() <= (uint)Index) { - mItems.push_back(item); + mItems.push_back(*item); SetDirty(); } - else if (mItems[Index] != item) { - mItems[Index] = item; + else if (mItems[Index] != *item) { + mItems[Index] = *item; SetDirty(); } + delete item; - if (Current && mCurrentItem != Index) { + if (Current && mCurrentItem != (uint)Index) { mCurrentItem = Index; SetDirty(); } + Dprintf("end SetItem()\n"); } void cText2SkinDisplayMenu::SetEvent(const cEvent *Event) { @@ -664,26 +673,28 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) { case tMenuItem: return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem != Token.Index + && mCurrentItem != (uint)Token.Index ? (cxType)mItems[Token.Index].tabs[Token.Tab] : (cxType)false; case tIsMenuItem: return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem != Token.Index; + && mCurrentItem != (uint)Token.Index; case tMenuCurrent: if (Token.Index < 0) - return mItems[mCurrentItem].text; + return mItems.size() > mCurrentItem + ? (cxType)mItems[mCurrentItem].text + : (cxType)false; return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem == Token.Index + && mCurrentItem == (uint)Token.Index ? (cxType)mItems[Token.Index].tabs[Token.Tab] : (cxType)false; case tIsMenuCurrent: return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem == Token.Index; + && mCurrentItem == (uint)Token.Index; case tMenuGroup: return mItems.size() > (uint)Token.Index && !mItems[Token.Index].sel @@ -1,5 +1,5 @@ /* - * $Id: display.h,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: display.h,v 1.5 2004/12/10 21:46:46 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_SKIN_H @@ -34,14 +34,15 @@ public: virtual void SetChannel(const cChannel *Channel, int Number); virtual void SetEvents(const cEvent *Present, const cEvent *Following); virtual void SetMessage(eMessageType Type, const char *Text); + virtual void SetButtons(const char *Red, const char *Green, const char *Yellow, const char *Blue); virtual void Flush(void); }; class cText2SkinDisplayVolume: public cSkinDisplayVolume, public cText2SkinRender { private: - int mCurrent; - int mTotal; - int mMute; + int mCurrent; + int mTotal; + bool mMute; protected: virtual cxType GetTokenData(const txToken &Token); @@ -128,11 +129,13 @@ private: std::string tabs[MaxTabs]; bool sel; + tListItem(const std::string &Text, bool Sel): text(Text), sel(Sel) {} + bool operator!=(const tListItem &b) { return b.text != text || b.sel != sel; } }; std::vector<tListItem> mItems; - int mCurrentItem; + uint mCurrentItem; protected: virtual cxType GetTokenData(const txToken &Token); @@ -16,15 +16,16 @@ void cText2SkinLoader::Start(void) { DIR *d = opendir(SkinPath().c_str()); if (d) { - struct dirent *ent; - while ((ent = readdir(d)) != NULL) { + struct dirent ent; + struct dirent *result; + while ((readdir_r(d, &ent, &result)) == 0 && result != NULL) { char *path; struct stat buf; - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) + if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) continue; - asprintf(&path, "%s/%s", SkinPath().c_str(), ent->d_name); + asprintf(&path, "%s/%s", SkinPath().c_str(), result->d_name); if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) - Load(ent->d_name); + Load(result->d_name); free(path); } closedir(d); diff --git a/quantize.c b/quantize.c new file mode 100644 index 0000000..84546f5 --- /dev/null +++ b/quantize.c @@ -0,0 +1,415 @@ +#include <stdio.h>
+#include <stdlib.h>
+
+#include "quantize.h"
+
+cQuantizeWu::cQuantizeWu()
+{
+}
+
+cQuantizeWu::~cQuantizeWu()
+{
+}
+
+#define WEIG //>>2
+int cQuantizeWu::Quantize(unsigned char * input, int size, int colors)
+{
+ struct box cube[MAXCOLOR];
+ int next;
+ int i;
+ int j;
+ int k;
+ int l;
+ float vv[MAXCOLOR];
+ float temp;
+ unsigned char * tag;
+ long weight;
+
+ imageInput = input;
+ imageSize = size;
+ palSize = colors;
+
+ for (j = 0; j < BOX; j++)
+ for (k = 0; k < BOX; k++)
+ for (l = 0; l < BOX; l++)
+ {
+ wt[j][k][l] = 0;
+ mr[j][k][l] = 0;
+ mg[j][k][l] = 0;
+ mb[j][k][l] = 0;
+ m2[j][k][l] = 0.0;
+ }
+
+ Qadd = new unsigned short[imageSize * sizeof(unsigned short)];
+ Hist3d((long *)&wt, (long *)&mr, (long *)&mg, (long *)&mb, (float *)&m2);
+ Momt3d((long *)&wt, (long *)&mr, (long *)&mg, (long *)&mb, (float *)&m2);
+
+ cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
+ cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
+
+ next = 0;
+ for (i = 1; i < palSize; i++)
+ {
+ if (Cut(&cube[next], &cube[i]))
+ {
+ vv[next] = (cube[next].vol > 1) ? Var(&cube[next]) : 0.0;
+ vv[i] = (cube[i].vol > 1) ? Var(&cube[i]) : 0.0;
+ }
+ else
+ {
+ vv[next] = 0.0;
+ i--;
+ }
+ next = 0;
+ temp = vv[0];
+ for (k = 1; k <= i; k++)
+ if (vv[k] > temp)
+ {
+ temp = vv[k];
+ next = k;
+ }
+ if (temp <= 0.0)
+ {
+ palSize = i + 1;
+ break;
+ }
+ }
+
+ tag = new unsigned char[BOX * BOX * BOX];
+
+ unsigned char * palette = (unsigned char *) paletteOutput;
+ for (k = 0; k < palSize; ++k)
+ {
+ Mark(&cube[k], k, tag);
+ weight = Vol(&cube[k], wt);
+ if (weight)
+ {
+#ifdef NOINVERT
+ palette[k * 4 + 2] = (Vol(&cube[k], mb) / weight) WEIG;
+ palette[k * 4 + 0] = (Vol(&cube[k], mr) / weight) WEIG;
+#else
+ palette[k * 4 + 0] = (Vol(&cube[k], mb) / weight) WEIG;
+ palette[k * 4 + 2] = (Vol(&cube[k], mr) / weight) WEIG;
+#endif
+ palette[k * 4 + 1] = (Vol(&cube[k], mg) / weight) WEIG;
+ }
+ else
+ {
+ palette[k * 4 + 0] = 0;
+ palette[k * 4 + 1] = 0;
+ palette[k * 4 + 2] = 0;
+ }
+ }
+
+ for (i = 0; i < imageSize; i++)
+ {
+ imageOutput[i] = tag[Qadd[i]];
+ }
+
+ delete[] tag;
+ delete[] Qadd;
+
+ return 0;
+}
+
+// build 3-D color histogram of counts, r/g/b, c^2
+void cQuantizeWu::Hist3d(long *vwt, long *vmr, long *vmg, long *vmb, float *m_2)
+{
+ int ind;
+ int r;
+ int g;
+ int b;
+ int inr;
+ int ing;
+ int inb;
+ int table[256];
+ int i;
+
+ for (i = 0; i < 256; i++)
+ table[i] = i * i;
+
+ for (i = 0; i < imageSize; i++)
+ {
+ b = imageInput[i*4];
+ g = imageInput[i*4+1];
+ r = imageInput[i*4+2];
+
+ inr = (r >> 3) + 1;
+ ing = (g >> 3) + 1;
+ inb = (b >> 3) + 1;
+ Qadd[i] = ind = (inr << 10) + (inr << 6) + inr + (ing << 5) + ing + inb;
+
+ vwt[ind]++;
+ vmr[ind] += r;
+ vmg[ind] += g;
+ vmb[ind] += b;
+ m_2[ind] += (float) (table[r] + table[g] + table[b]);
+ }
+}
+
+// We now convert histogram into moments so that we can rapidly calculate
+// the sums of the above quantities over any desired box.
+void cQuantizeWu::Momt3d(long *vwt, long *vmr, long *vmg, long *vmb, float *m_2)
+{
+ unsigned short ind1;
+ unsigned short ind2;
+ unsigned char i;
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
+ long line;
+ long line_r;
+ long line_g;
+ long line_b;
+ long area[BOX];
+ long area_r[BOX];
+ long area_g[BOX];
+ long area_b[BOX];
+ float line2;
+ float area2[BOX];
+
+ for (r = 1; r <= 32; ++r)
+ {
+ for (i = 0; i <= 32; ++i)
+ area2[i] = area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
+ for (g = 1; g <= 32; ++g)
+ {
+ line2 = line = line_r = line_g = line_b = 0;
+ for (b = 1; b <= 32; ++b)
+ {
+ ind1 = (r << 10) + (r << 6) + r + (g << 5) + g + b;
+ line += vwt[ind1];
+ line_r += vmr[ind1];
+ line_g += vmg[ind1];
+ line_b += vmb[ind1];
+ line2 += m_2[ind1];
+ area[b] += line;
+ area_r[b] += line_r;
+ area_g[b] += line_g;
+ area_b[b] += line_b;
+ area2[b] += line2;
+ ind2 = ind1 - 1089; /* [r-1][g][b] */
+ vwt[ind1] = vwt[ind2] + area[b];
+ vmr[ind1] = vmr[ind2] + area_r[b];
+ vmg[ind1] = vmg[ind2] + area_g[b];
+ vmb[ind1] = vmb[ind2] + area_b[b];
+ m_2[ind1] = m_2[ind2] + area2[b];
+ }
+ }
+ }
+}
+
+int cQuantizeWu::Cut(struct box * set1, struct box * set2)
+{
+ unsigned char dir;
+ int cutr;
+ int cutg;
+ int cutb;
+ float maxr;
+ float maxg;
+ float maxb;
+ long whole_r;
+ long whole_g;
+ long whole_b;
+ long whole_w;
+
+ whole_r = Vol(set1, mr);
+ whole_g = Vol(set1, mg);
+ whole_b = Vol(set1, mb);
+ whole_w = Vol(set1, wt);
+
+ maxr = Maximize(set1, RED, set1->r0 + 1, set1->r1, &cutr,
+ whole_r, whole_g, whole_b, whole_w);
+ maxg = Maximize(set1, GREEN, set1->g0 + 1, set1->g1, &cutg,
+ whole_r, whole_g, whole_b, whole_w);
+ maxb = Maximize(set1, BLUE, set1->b0 + 1, set1->b1, &cutb,
+ whole_r, whole_g, whole_b, whole_w);
+
+ if ((maxr >= maxg) && (maxr >= maxb))
+ {
+ dir = RED;
+ if (cutr < 0)
+ return 0; /* can't split the box */
+ }
+ else if ((maxg >= maxr) && (maxg >= maxb))
+ dir = GREEN;
+ else
+ dir = BLUE;
+
+ set2->r1 = set1->r1;
+ set2->g1 = set1->g1;
+ set2->b1 = set1->b1;
+
+ switch (dir)
+ {
+ case RED:
+ set2->r0 = set1->r1 = cutr;
+ set2->g0 = set1->g0;
+ set2->b0 = set1->b0;
+ break;
+ case GREEN:
+ set2->g0 = set1->g1 = cutg;
+ set2->r0 = set1->r0;
+ set2->b0 = set1->b0;
+ break;
+ case BLUE:
+ set2->b0 = set1->b1 = cutb;
+ set2->r0 = set1->r0;
+ set2->g0 = set1->g0;
+ break;
+ }
+ set1->vol = (set1->r1 - set1->r0) * (set1->g1 - set1->g0) * (set1->b1 - set1->b0);
+ set2->vol = (set2->r1 - set2->r0) * (set2->g1 - set2->g0) * (set2->b1 - set2->b0);
+ return 1;
+}
+
+long cQuantizeWu::Vol(struct box * cube, long mmt[BOX][BOX][BOX])
+{
+ return (mmt[cube->r1][cube->g1][cube->b1]
+ - mmt[cube->r1][cube->g1][cube->b0]
+ - mmt[cube->r1][cube->g0][cube->b1]
+ + mmt[cube->r1][cube->g0][cube->b0]
+ - mmt[cube->r0][cube->g1][cube->b1]
+ + mmt[cube->r0][cube->g1][cube->b0]
+ + mmt[cube->r0][cube->g0][cube->b1]
+ - mmt[cube->r0][cube->g0][cube->b0]);
+}
+
+float cQuantizeWu::Maximize(struct box * cube, unsigned char dir, int first, int last, int * cut, long whole_r, long whole_g, long whole_b, long whole_w)
+{
+ long half_r;
+ long half_g;
+ long half_b;
+ long half_w;
+ long base_r;
+ long base_g;
+ long base_b;
+ long base_w;
+ int i;
+ float temp;
+ float max;
+
+ base_r = Bottom(cube, dir, mr);
+ base_g = Bottom(cube, dir, mg);
+ base_b = Bottom(cube, dir, mb);
+ base_w = Bottom(cube, dir, wt);
+ max = 0.0;
+ *cut = -1;
+ for (i = first; i < last; i++)
+ {
+ half_r = base_r + Top(cube, dir, i, mr);
+ half_g = base_g + Top(cube, dir, i, mg);
+ half_b = base_b + Top(cube, dir, i, mb);
+ half_w = base_w + Top(cube, dir, i, wt);
+ // now half_x is sum over lower half of box, if split at i
+ if (half_w == 0)
+ {
+ // subbox could be empty of pixels!
+ continue; // never split into an empty box
+ }
+ else
+ temp = ((float) half_r * half_r + (float) half_g * half_g + (float) half_b * half_b) / half_w;
+
+ half_r = whole_r - half_r;
+ half_g = whole_g - half_g;
+ half_b = whole_b - half_b;
+ half_w = whole_w - half_w;
+ if (half_w == 0)
+ {
+ // subbox could be empty of pixels!
+ continue; // never split into an empty box
+ }
+ else
+ temp += ((float) half_r * half_r + (float) half_g * half_g + (float) half_b * half_b) / half_w;
+
+ if (temp > max)
+ {
+ max = temp;
+ *cut = i;
+ }
+ }
+ return (max);
+}
+
+float cQuantizeWu::Var(struct box * cube)
+{
+ float dr;
+ float dg;
+ float db;
+ float xx;
+
+ dr = Vol(cube, mr);
+ dg = Vol(cube, mg);
+ db = Vol(cube, mb);
+ xx = m2[cube->r1][cube->g1][cube->b1]
+ - m2[cube->r1][cube->g1][cube->b0]
+ - m2[cube->r1][cube->g0][cube->b1]
+ + m2[cube->r1][cube->g0][cube->b0]
+ - m2[cube->r0][cube->g1][cube->b1]
+ + m2[cube->r0][cube->g1][cube->b0]
+ + m2[cube->r0][cube->g0][cube->b1]
+ - m2[cube->r0][cube->g0][cube->b0];
+
+ return (xx - (dr * dr + dg * dg + db * db) / (float) Vol(cube, wt));
+}
+
+long cQuantizeWu::Bottom(struct box * cube, unsigned char dir, long mmt[BOX][BOX][BOX])
+{
+ switch (dir)
+ {
+ case RED:
+ return (-mmt[cube->r0][cube->g1][cube->b1]
+ + mmt[cube->r0][cube->g1][cube->b0]
+ + mmt[cube->r0][cube->g0][cube->b1]
+ - mmt[cube->r0][cube->g0][cube->b0]);
+ case GREEN:
+ return (-mmt[cube->r1][cube->g0][cube->b1]
+ + mmt[cube->r1][cube->g0][cube->b0]
+ + mmt[cube->r0][cube->g0][cube->b1]
+ - mmt[cube->r0][cube->g0][cube->b0]);
+ case BLUE:
+ return (-mmt[cube->r1][cube->g1][cube->b0]
+ + mmt[cube->r1][cube->g0][cube->b0]
+ + mmt[cube->r0][cube->g1][cube->b0]
+ - mmt[cube->r0][cube->g0][cube->b0]);
+ }
+ printf("error in Bottom()");
+ return 0;
+}
+
+long cQuantizeWu::Top(struct box * cube, unsigned char dir, int pos, long mmt[BOX][BOX][BOX])
+{
+ switch (dir)
+ {
+ case RED:
+ return (mmt[pos][cube->g1][cube->b1]
+ - mmt[pos][cube->g1][cube->b0]
+ - mmt[pos][cube->g0][cube->b1]
+ + mmt[pos][cube->g0][cube->b0]);
+ case GREEN:
+ return (mmt[cube->r1][pos][cube->b1]
+ - mmt[cube->r1][pos][cube->b0]
+ - mmt[cube->r0][pos][cube->b1]
+ + mmt[cube->r0][pos][cube->b0]);
+ case BLUE:
+ return (mmt[cube->r1][cube->g1][pos]
+ - mmt[cube->r1][cube->g0][pos]
+ - mmt[cube->r0][cube->g1][pos]
+ + mmt[cube->r0][cube->g0][pos]);
+ }
+ printf("error in Top()");
+ return 0;
+}
+
+void cQuantizeWu::Mark(struct box * cube, int label, unsigned char * tag)
+{
+ int r;
+ int g;
+ int b;
+
+ for (r = cube->r0 + 1; r <= cube->r1; r++)
+ for (g = cube->g0 + 1; g <= cube->g1; g++)
+ for (b = cube->b0 + 1; b <= cube->b1; b++)
+ tag[(r << 10) + (r << 6) + r + (g << 5) + g + b] = label;
+
+}
diff --git a/quantize.h b/quantize.h new file mode 100644 index 0000000..af6a623 --- /dev/null +++ b/quantize.h @@ -0,0 +1,71 @@ +#ifndef VDR_GRAPHTFT_QUANTIZE_H
+#define VDR_GRAPHTFT_QUANTIZE_H
+
+#define MAXCOLOR 256
+
+class cQuantize
+{
+protected:
+ unsigned int paletteOutput[MAXCOLOR];
+ unsigned char imageOutput[1024*1024];
+public:
+ cQuantize(){};
+ virtual ~cQuantize(){};
+ virtual int Quantize(unsigned char * input, int size, int colors) = 0;
+ unsigned int * OutputPalette() { return paletteOutput; }
+ unsigned char * OutputImage() { return imageOutput; }
+};
+
+#define RED 2
+#define GREEN 1
+#define BLUE 0
+
+//#define NOINVERT // RGB or BGR
+
+struct box
+{
+ int r0;
+ int r1;
+ int g0;
+ int g1;
+ int b0;
+ int b1;
+ int vol;
+};
+
+// Histogram is in elements 1..HISTSIZE along each axis,
+// element 0 is for base or marginal value.
+// NB: these must start out 0!
+#define BOX 33
+
+class cQuantizeWu : public cQuantize
+{
+private:
+ long wt[BOX][BOX][BOX];
+ long mr[BOX][BOX][BOX];
+ long mg[BOX][BOX][BOX];
+ long mb[BOX][BOX][BOX];
+ float m2[BOX][BOX][BOX];
+
+ unsigned short * Qadd;
+
+ unsigned char * imageInput;
+ int imageSize;
+ int palSize;
+
+ void Hist3d(long *vwt, long *vmr, long *vmg, long *vmb, float *m_2);
+ void Momt3d(long *vwt, long *vmr, long *vmg, long *vmb, float *m_2);
+ int Cut(struct box * set1, struct box * set2);
+ long Vol(struct box * cube, long mmt[BOX][BOX][BOX]);
+ float Maximize(struct box * cube, unsigned char dir, int first, int last, int * cut, long whole_r, long whole_g, long whole_b, long whole_w);
+ float Var(struct box * cube);
+ long Top(struct box * cube, unsigned char dir, int pos, long mmt[BOX][BOX][BOX]);
+ long Bottom(struct box * cube, unsigned char dir, long mmt[BOX][BOX][BOX]);
+ void Mark(struct box * cube, int label, unsigned char * tag);
+public:
+ cQuantizeWu();
+ virtual ~cQuantizeWu();
+ virtual int Quantize(unsigned char * input, int size, int colors);
+};
+
+#endif // VDR_GRAPHTFT_QUANTIZE_H
@@ -1,5 +1,5 @@ /* - * $Id: render.c,v 1.6 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: render.c,v 1.7 2004/12/10 21:46:46 lordjaxom Exp $ */ #include "render.h" @@ -28,7 +28,9 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Di mDirty(true), mActive(false), mDoUpdate(), - mMutex(), + mDoUpdateMutex(), + //mDoneUpdate(), + //mDoneUpdateMutex(), mStarted(), mUpdateIn(0), mBaseSize() @@ -87,10 +89,10 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Di } if (!OffScreen) { - Lock(); + mDoUpdateMutex.Lock(); Start(); - mStarted.Wait(mMutex); - Unlock(); + mStarted.Wait(mDoUpdateMutex); + mDoUpdateMutex.Unlock(); } } @@ -108,18 +110,22 @@ cText2SkinRender::~cText2SkinRender() { void cText2SkinRender::Action(void) { mActive = true; - Lock(); + mDoUpdateMutex.Lock(); mStarted.Broadcast(); while (mActive) { - if (mUpdateIn) mDoUpdate.TimedWait(mMutex, mUpdateIn); - else mDoUpdate.Wait(mMutex); + if (mUpdateIn) mDoUpdate.TimedWait(mDoUpdateMutex, mUpdateIn); + else mDoUpdate.Wait(mDoUpdateMutex); - if (!mActive) break; // fall out if thread to be stopped + if (!mActive) break; // fall out if thread to be stopped mUpdateIn = 0; // has to be re-set within Update(); Update(); + + //mDoneUpdateMutex.Lock(); + //mDoneUpdate.Broadcast(); + //mDoneUpdateMutex.Unlock(); } - Unlock(); + mDoUpdateMutex.Unlock(); } void cText2SkinRender::Update(void) { @@ -243,7 +249,7 @@ void cText2SkinRender::DrawImage(const txPoint &Pos, const tColor *Bg, const tCo const std::string &Path) { cText2SkinBitmap *bmp; - //Dprintf("trying to draw image %s to %dx%d\n", ImagePath(Path).c_str(), Pos.x, Pos.y); + Dprintf("trying to draw image %s to %dx%d - alpha %d\n", ImagePath(Path).c_str(), Pos.x, Pos.y, Alpha); if ((bmp = cText2SkinBitmap::Load(ImagePath(Path), Alpha)) != NULL) { //Dprintf("success loading image\n"); if (Bg) bmp->SetColor(0, *Bg); @@ -1,5 +1,5 @@ /* - * $Id: render.h,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: render.h,v 1.6 2004/12/10 21:46:46 lordjaxom Exp $ */ #ifndef VDR_TEXT2SKIN_RENDER_H @@ -45,8 +45,11 @@ private: // update thread bool mActive; + cCondVar mDoUpdate; - cMutex mMutex; + cMutex mDoUpdateMutex; + //cCondVar mDoneUpdate; + //cMutex mDoneUpdateMutex; cCondVar mStarted; int mUpdateIn; @@ -55,8 +58,8 @@ private: protected: // Update thread - void Lock(void) { mMutex.Lock(); } - void Unlock(void) { mMutex.Unlock(); } + //void Lock(void) { mMutex.Lock(); } + //void Unlock(void) { mMutex.Unlock(); } virtual void Action(void); // Drawing operations @@ -115,9 +118,19 @@ public: inline void cText2SkinRender::Flush(bool Force) { if (mDirty || Force) { - Lock(); + //mDoneUpdateMutex.Lock(); + + mDoUpdateMutex.Lock(); mDoUpdate.Broadcast(); - Unlock(); + mDoUpdateMutex.Unlock(); + + //if (mActive) { + //Dprintf("flush wait\n"); + //mDoneUpdate.Wait(mDoneUpdateMutex); + //Dprintf("flush wait done\n"); + //} + //mDoneUpdateMutex.Unlock(); + mDirty = false; } } diff --git a/text2skin.c b/text2skin.c index e9baa04..3c73107 100644 --- a/text2skin.c +++ b/text2skin.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: text2skin.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $ + * $Id: text2skin.c,v 1.3 2004/12/10 21:46:46 lordjaxom Exp $ */ #include "text2skin.h" @@ -12,7 +12,7 @@ #include "i18n.h" #include "loader.h" -const char *cText2SkinPlugin::VERSION = "1.0-pre2"; +const char *cText2SkinPlugin::VERSION = "1.0-pre3"; const char *cText2SkinPlugin::SKINVERSION = "1.0"; const char *cText2SkinPlugin::DESCRIPTION = "Loader for text-based skins"; diff --git a/xml/function.c b/xml/function.c index f283c2c..3243257 100644 --- a/xml/function.c +++ b/xml/function.c @@ -1,15 +1,16 @@ /* - * $Id: function.c,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $ + * $Id: function.c,v 1.5 2004/12/10 21:46:46 lordjaxom Exp $ */ #include "xml/function.h" #include "render.h" #include "bitmap.h" #include "common.h" +#include <vdr/plugin.h> #include <vdr/tools.h> static const char *Internals[] = { - "not", "and", "or", "equal", "file", "trans", NULL + "not", "and", "or", "equal", "file", "trans", "plugin", NULL }; const std::string cxFunction::False = ""; @@ -129,6 +130,7 @@ bool cxFunction::Parse(const std::string &Text) case fun_eq: ++params; case fun_not: case fun_trans: + case fun_plugin: case fun_file: ++params; default: break; } @@ -161,6 +163,19 @@ const std::string &cxFunction::FunFile(const std::string &Param) const return cText2SkinBitmap::Load(path) ? Param : False; } +std::string cxFunction::FunPlugin(const std::string &Param) const +{ + Dprintf("FunPlugin: Get(%s)\n", Param.c_str()); + cPlugin *p = cPluginManager::GetPlugin(Param.c_str()); + if (p) { + const char *entry = p->MainMenuEntry(); + Dprintf("Entry: |%s|\n", entry); + if (entry) + return entry; + } + return False; +} + std::string cxFunction::Evaluate(void) const { switch (mType) { @@ -185,6 +200,7 @@ std::string cxFunction::Evaluate(void) const return False; case fun_eq: + Dprintf("eq: |%s| <-> |%s|\n", mParams[0]->Evaluate().c_str(), mParams[1]->Evaluate().c_str()); return mParams[0]->Evaluate() == mParams[1]->Evaluate() ? True : False; case fun_file: @@ -192,6 +208,9 @@ std::string cxFunction::Evaluate(void) const case fun_trans: return tr(mParams[0]->Evaluate().c_str()); + + case fun_plugin: + return FunPlugin(mParams[0]->Evaluate()); default: Dprintf("unknown function code\n"); diff --git a/xml/function.h b/xml/function.h index a7d8838..49928af 100644 --- a/xml/function.h +++ b/xml/function.h @@ -27,7 +27,8 @@ public: fun_or = INTERNAL + 3, fun_eq = INTERNAL + 4, fun_file = INTERNAL + 5, - fun_trans = INTERNAL + 6 + fun_trans = INTERNAL + 6, + fun_plugin = INTERNAL + 7 }; static const std::string False; @@ -42,6 +43,7 @@ private: protected: const std::string &FunFile(const std::string &Param) const; + std::string FunPlugin(const std::string &Param) const; public: cxFunction(void); diff --git a/xml/parser.c b/xml/parser.c index 4b957be..8842d19 100644 --- a/xml/parser.c +++ b/xml/parser.c @@ -1,5 +1,5 @@ /* - * $Id: parser.c,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $ + * $Id: parser.c,v 1.5 2004/12/10 21:46:46 lordjaxom Exp $ */ #include "xml/parser.h" @@ -11,49 +11,6 @@ #include <vector> #include <string> -#define STR_SKIN "skin" -#define STR_DISPLAY "display" -#define STR_ID "id" -#define STR_WINDOW "window" -#define STR_X1 "x1" -#define STR_Y1 "y1" -#define STR_X "x" -#define STR_Y "y" -#define STR_X2 "x2" -#define STR_Y2 "y2" -#define STR_BPP "bpp" -#define STR_IMAGE "image" -#define STR_PATH "path" -#define STR_ALPHA "alpha" -#define STR_TEXT "text" -#define STR_CONDITION "condition" -#define STR_NOT "not" -#define STR_FILE "file" -#define STR_COLOR "color" -#define STR_ALIGN "align" -#define STR_RECTANGLE "rectangle" -#define STR_ELLIPSE "ellipse" -#define STR_SLOPE "slope" -#define STR_PROGRESS "progress" -#define STR_BGCOLOR "bgcolor" -#define STR_CURRENT "current" -#define STR_TOTAL "total" -#define STR_VERSION "version" -#define STR_NAME "name" -#define STR_SCREENBASE "screenBase" -#define STR_FONT "font" -#define STR_ARC "arc" - -#define MSG_BADTAG "ERROR: The tag %s was not expected in this context" -#define MSG_BADENDTAG "ERROR: The tag %s was not expected in this context" -#define MSG_BADATTR "ERROR: The attribute %s was not expected in tag %s" -#define MSG_MISSATTR "ERROR: The tag %s lacks the attribute %s" -#define MSG_BADVALUE "ERROR: %s is not allowed for attribute %s" -#define MSG_PARSERR "ERROR: Parser error in %s:%d: %s" -#define MSG_BADCDATA "ERROR: Bad character data" -#define MSG_NOFILE "ERROR: Couldn't read %s: %m" -#define MSG_MANYWINS "ERROR: Too many windows" - #define TAG_ERR_REMAIN(_context) do { \ esyslog("ERROR: Text2Skin: Unexpected tag %s within %s", \ name.c_str(), _context); \ @@ -132,7 +89,7 @@ static cxObject *parent = NULL; static cxObject *object = NULL; bool xStartElem(const std::string &name, std::map<std::string,std::string> &attrs) { - Dprintf("start element: %s\n", name.c_str()); + //Dprintf("start element: %s\n", name.c_str()); if (context.size() == 0) { if (name == "skin") { @@ -227,7 +184,7 @@ bool xStartElem(const std::string &name, std::map<std::string,std::string> &attr bool xCharData(const std::string &text) { int start = 0, end = text.length() - 1; - Dprintf("char data before: %s\n", text.c_str()); + //Dprintf("char data before: %s\n", text.c_str()); while (text[start] == '\012' || text[start] == '\015' || text[start] == ' ' || text[start] == '\t') ++start; @@ -235,22 +192,22 @@ bool xCharData(const std::string &text) { while (text[end] == '\012' || text[end] == '\015' || text[end] == ' ' || text[end] == '\t') --end; - Dprintf("char data after: %s\n", text.substr(start, end - start + 1).c_str()); + //Dprintf("char data after: %s\n", text.substr(start, end - start + 1).c_str()); if (end - start + 1 > 0) { - Dprintf("context: %s\n", context[context.size() - 1].c_str()); + //Dprintf("context: %s\n", context[context.size() - 1].c_str()); if (context[context.size() - 1] == "text" || context[context.size() - 1] == "scrolltext") { if (!object->mText.Parse(text.substr(start, end - start + 1))) return false; } else - esyslog(MSG_BADCDATA); + esyslog("ERROR: Bad character data"); } return true; } bool xEndElem(const std::string &name) { - Dprintf("end element: %s\n", name.c_str()); + //Dprintf("end element: %s\n", name.c_str()); if (context[context.size() - 1] == name) { if (name == "display") { skin->mDisplays[display->Type()] = display; @@ -258,7 +215,7 @@ bool xEndElem(const std::string &name) { } else if (object != NULL || parent != NULL) { if (object == NULL) { - Dprintf("rotating parent to object\n"); + //Dprintf("rotating parent to object\n"); object = parent; parent = NULL; } @@ -275,7 +232,7 @@ bool xEndElem(const std::string &name) { } if (parent != NULL) { - Dprintf("pushing to parent\n"); + //Dprintf("pushing to parent\n"); if (parent->mObjects == NULL) parent->mObjects = new cxObjects(); parent->mObjects->push_back(object); diff --git a/xml/string.c b/xml/string.c index 051a003..269aa0f 100644 --- a/xml/string.c +++ b/xml/string.c @@ -91,6 +91,7 @@ bool cxString::Parse(const std::string &Text) { int pos = -1; txToken &lastToken = mTokens[mTokens.size() - 1]; + Dprintf("assigning attrib: %.*s\n", ptr-last, last); lastToken.Attrib.assign(last, ptr - last); while ((pos = lastToken.Attrib.find('\\', pos + 1)) != -1) { switch (lastToken.Attrib[pos + 1]) { @@ -7,11 +7,12 @@ #include <stdio.h> const std::string &cxType::String(void) { - static char buffer[50]; if (mType == number) { - snprintf(buffer, sizeof(buffer), "%d", mNumber); + char *buffer; + asprintf(&buffer, "%d", mNumber); mString = buffer; mType = string; + free(buffer); } else if (mType == boolean) { mString = mNumber ? cxFunction::True : cxFunction::False; mType = string; @@ -5,6 +5,7 @@ #ifndef VDR_TEXT2SKIN_XML_TYPE_H #define VDR_TEXT2SKIN_XML_TYPE_H +#include <stdio.h> #include <string> class cxType { @@ -26,6 +27,7 @@ public: cxType(int Number): mType(number), mNumber(Number) {} cxType(time_t Number): mType(number), mNumber(Number) {} cxType(bool Value): mType(boolean), mNumber(Value ? 1 : 0) {} + cxType(const cxType &Src): mType(Src.mType), mString(Src.mString), mNumber(Src.mNumber) {} const std::string &String(void); int Number(void) const; @@ -16,6 +16,9 @@ enum { LOOK4START, // looking for first element start LOOK4TAG, // looking for element tag INTAG, // reading tag + INCOMMENT, // reading comment + LOOK4CEND1, // looking for second '-' in --> + LOOK4CEND2, // looking for '>' in --> LOOK4ATTRN, // looking for attr name, > or / INATTRN, // reading attr name LOOK4ATTRV, // looking for attr value @@ -149,7 +152,7 @@ XML::readChar(int c) { } break; } else { - if (c == '?' || c == '!') { + if (c == '?') { skipping = true; break; } @@ -159,6 +162,8 @@ XML::readChar(int c) { state = INTAG; } else if (c == '/') { state = LOOK4CLOSETAG; + } else if (c == '!') { + state = INCOMMENT; } else if (!isspace(c)) { if (parseerrorcb) { parseerrorcb(linenr, "Bogus tag char", c); @@ -183,6 +188,31 @@ XML::readChar(int c) { } break; + // reading comment + case INCOMMENT: + if (c == '-') { + state = LOOK4CEND1; + } + break; + + // looking for second '-' in "-->" + case LOOK4CEND1: + if (c == '-') { + state = LOOK4CEND2; + } else { + state = INCOMMENT; + } + break; + + // looking for '>' in "-->" + case LOOK4CEND2: + if (c == '>') { + state = LOOK4START; + } else if (c != '-') { + state = INCOMMENT; + } + break; + // looking for attr name, > or / case LOOK4ATTRN: if (c == '>') { |