/* * Spider-Arachnid: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * * $Id$ */ #include "bitmap.h" #include <vdr/config.h> #include <vdr/osdbase.h> #include <vdr/osd.h> #include <ctype.h> // Compatibility to older vdr versions #if VDRVERSNUM < 10307 #define tColor eDvbColor #define DrawRectangle Fill #define DrawPixel SetPixel #endif /** --- class Bitmap ------------------------------------------------------- **/ /** Constructor */ Bitmap::Bitmap(int width, int height) : cBitmap(width, height, 4) { } /** Constructor for a bitmap with frame */ Bitmap::Bitmap(int width, int height, tColor frameColor, tColor backgroundColor) : cBitmap(width, height, 4) { DrawRectangle(0, 0, width - 1, height - 1, backgroundColor); frame(0, 0, width - 1, height - 1, frameColor); } /** Constructor for a bitmap read from an xpm file */ Bitmap::Bitmap(int width, int height, const char* dir, const char* name) : cBitmap(width, height, 4) { char* path; asprintf(&path, "%s/%s.xpm", dir, name); loadXpm(path); free(path); } /** Constructor for a card bitmap read from an xpm file */ Bitmap::Bitmap(int width, int height, const char* dir, const char* suit, const char* rank) : cBitmap(width, height, 4) { char* path; asprintf(&path, "%s/%s_%s.xpm", dir, suit, rank); loadXpm(path); free(path); } /** Write a text into the bitmap */ void Bitmap::text(const char* text, bool centered) { DrawRectangle(0, 0, Width() - 1, Height() - 1, clrWhite); frame(0, 0, Width() - 1, Height() - 1, clrRed); #if VDRVERSNUM < 10307 SetFont(fontOsd); int lineCount; char* wrapper = textWrapper(text, &lineCount); int y = max((Height() - lineCount * cOsd::LineHeight()) / 2, 0); char* line = wrapper; while (*line) { char* newline = strchr(line, '\n'); if (newline) *newline = 0; int x = 0; if (centered) x = max((Width() - Width(line)) / 2, 0); Text(x, y, line, clrBlack, clrWhite); if (newline) *newline = '\n'; if (!newline) break; line = newline + 1; y += cOsd::LineHeight(); } free(wrapper); #else const cFont* font = cFont::GetFont(fontOsd); cTextWrapper wrapper(text, font, Width()); int y = max((Height() - wrapper.Lines() * font->Height()) / 2, 0); for (int l = 0; l < wrapper.Lines(); ++l, y += font->Height()) { int x = 0; if (centered) x = max((Width() - font->Width(wrapper.GetLine(l))) / 2, 0); DrawText(x, y, wrapper.GetLine(l), clrBlack, clrWhite, font); } #endif } /** Draw a frame into the bitmap */ void Bitmap::frame(int x1, int y1, int x2, int y2, tColor frameColor) { DrawRectangle(x1, y1, x2, y1 + 1, frameColor); DrawRectangle(x1, y1, x1 + 1, y2, frameColor); DrawRectangle(x1, y2 - 1, x2, y2, frameColor); DrawRectangle(x2 - 1, y1, x2, y2, frameColor); } /** Load a bitmap from an xpm file - taken from ElchiAIO4d patch */ bool Bitmap::loadXpm(const char* FileName, tColor NoneColor) { bool bRet = false; FILE *infile; infile = fopen(FileName, "r"); if (infile) { bool ok = true; char buf[512]; char *ptr; int state = 0; int width, height, colors, colwidth, cnt = 0; int temp; uint pal[65536]; while (ok && fgets(buf, sizeof(buf), infile) != NULL) { int len = strlen(buf); ptr = buf; if (ptr[len - 1] == '\n') ptr[--len] = '\0'; if (state > 0 && strncmp(ptr, "/*", 2) == 0) { continue; } switch (state) { case 0: if (strcmp(ptr, "/* XPM */") != 0) { esyslog("ERROR: loading xpm %s failed: invalid header", FileName); ok = false; break; } ++state; break; case 1: ++state; break; case 2: sscanf(ptr, "\"%d %d %d %d\",", &width, &height, &colors, &colwidth); if (colwidth > 2) { esyslog("ERROR: wrong colorwidth in xpm %s", FileName); ok = false; break; } cnt = 0; ++state; break; case 3: ++ptr; temp = 0; for (int i = 0; i < colwidth; ++i) { temp <<= 8; temp += (int)*ptr; ++ptr; } ++ptr; if (strncmp(ptr, "c ", 2) != 0) { esyslog("ERROR: wrong character in xpm %s", FileName); ok = false; break; } ptr += 2; if (*ptr == '#') { int col = strtoul(++ptr, NULL, 16); #if VDRVERSNUM < 10307 pal[temp] = 0xff000000 | ((col & 0xff) << 16) | (col & 0xff00) | ((col & 0xff0000) >> 16); #else pal[temp] = 0xff000000 | col; #endif } else { pal[temp] = NoneColor; } if (++cnt == colors) { cnt = 0; ++state; } break; case 4: ++ptr; for (int p = 0; p < width; ++p) { temp = 0; for (int i = 0; i < colwidth; ++i) { temp <<= 8; temp += (int)*ptr; ++ptr; } DrawPixel(p, cnt, (tColor)pal[temp]); } if (++cnt == height) { ++state; bRet = true; } break; default: break; } } fclose(infile); } return bRet; } #if VDRVERSNUM < 10307 /** Wrap the text to fit into the bitmap - taken from font.c in VDR 1.3.7 */ char *Bitmap::textWrapper(const char *Text, int *p_lines) { char *text = strdup(Text); int lines = 1; char *Blank = NULL; char *Delim = NULL; int w = 0; stripspace(text); // strips trailing newlines for (char *p = text; *p; ) { if (*p == '\n') { lines++; w = 0; Blank = Delim = NULL; p++; continue; } else if (isspace(*p)) Blank = p; int cw = Width(*p); if (w + cw > Width()) { if (Blank) { *Blank = '\n'; p = Blank; continue; } else { // Here's the ugly part, where we don't have any whitespace to // punch in a newline, so we need to make room for it: if (Delim) p = Delim + 1; // let's fall back to the most recent delimiter char *s = MALLOC(char, strlen(text) + 2); // The additional '\n' plus the terminating '\0' int l = p - text; strncpy(s, text, l); s[l] = '\n'; strcpy(s + l + 1, p); free(text); text = s; p = text + l; continue; } } else w += cw; if (strchr("-.,:;!?_", *p)) { Delim = p; Blank = NULL; } p++; } if (p_lines != NULL) *p_lines = lines; return text; } #endif