diff options
Diffstat (limited to 'glcdgraphics')
-rw-r--r-- | glcdgraphics/Makefile | 68 | ||||
-rw-r--r-- | glcdgraphics/bitmap.c | 807 | ||||
-rw-r--r-- | glcdgraphics/bitmap.h | 75 | ||||
-rw-r--r-- | glcdgraphics/common.c | 60 | ||||
-rw-r--r-- | glcdgraphics/common.h | 26 | ||||
-rw-r--r-- | glcdgraphics/font.c | 581 | ||||
-rw-r--r-- | glcdgraphics/font.h | 75 | ||||
-rw-r--r-- | glcdgraphics/glcd.c | 277 | ||||
-rw-r--r-- | glcdgraphics/glcd.h | 36 | ||||
-rw-r--r-- | glcdgraphics/image.c | 67 | ||||
-rw-r--r-- | glcdgraphics/image.h | 58 | ||||
-rw-r--r-- | glcdgraphics/imagefile.c | 35 | ||||
-rw-r--r-- | glcdgraphics/imagefile.h | 33 | ||||
-rw-r--r-- | glcdgraphics/pbm.c | 187 | ||||
-rw-r--r-- | glcdgraphics/pbm.h | 34 |
15 files changed, 2419 insertions, 0 deletions
diff --git a/glcdgraphics/Makefile b/glcdgraphics/Makefile new file mode 100644 index 0000000..fb072ab --- /dev/null +++ b/glcdgraphics/Makefile @@ -0,0 +1,68 @@ +# +# Makefile for the GraphLCD graphics library +# + +-include ../Make.config + +CXXFLAGS += -fPIC + +VERMAJOR = 2 +VERMINOR = 0 +VERMICRO = 0 + +BASENAME = libglcdgraphics.so + +LIBNAME = $(BASENAME).$(VERMAJOR).$(VERMINOR).$(VERMICRO) + +OBJS = bitmap.o common.o font.o glcd.o image.o imagefile.o pbm.o + +HEADERS = bitmap.h font.h glcd.h image.h imagefile.h pbm.h + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +# Dependencies: + +MAKEDEP = g++ -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +ifdef HAVE_FREETYPE2 + ifneq ($(shell which freetype-config),) + INCLUDES += $(shell freetype-config --cflags) + LIBS += $(shell freetype-config --libs) + else + INCLUDES += -I/usr/include/freetype -I/usr/local/include/freetype + LIBS += -lfreetype + endif + DEFINES += -DHAVE_FREETYPE2 +endif### Targets: + +all: $(LIBNAME) + +$(LIBNAME): $(OBJS) + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -Wl,-soname="$(BASENAME).$(VERMAJOR)" -o $@ + ln -sf $(LIBNAME) $(BASENAME) + +install: all + install -d $(LIBDIR) + install -m 755 $(LIBNAME) $(LIBDIR)/ + install -d $(INCDIR)/glcdgraphics + install -m 644 $(HEADERS) $(INCDIR)/glcdgraphics/ + ( cd $(LIBDIR); ln -sf $(LIBNAME) $(BASENAME).$(VERMAJOR); ln -sf $(LIBNAME) $(BASENAME) ) + +uninstall: + rm -f $(LIBDIR)/$(BASENAME) + rm -f $(LIBDIR)/$(BASENAME).$(VERMAJOR) + rm -f $(LIBDIR)/$(LIBNAME) + (for i in $(HEADERS); do rm -f $(INCDIR)/glcdgraphics/$$i; done) + rmdir $(INCDIR)/glcdgraphics + +clean: + rm -f $(OBJS) $(DEPFILE) $(LIBNAME) $(BASENAME) *~ + diff --git a/glcdgraphics/bitmap.c b/glcdgraphics/bitmap.c new file mode 100644 index 0000000..d5ba159 --- /dev/null +++ b/glcdgraphics/bitmap.c @@ -0,0 +1,807 @@ +/* + * GraphLCD graphics library + * + * bitmap.c - cBitmap class + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "bitmap.h" +#include "common.h" +#include "font.h" + + +namespace GLCD +{ + +const unsigned char bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; +const unsigned char bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; +const unsigned char bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; + +cBitmap::cBitmap(int width, int height, unsigned char * data) +: width(width), + height(height), + bitmap(NULL) +{ + // lines are byte aligned + lineSize = (width + 7) / 8; + + bitmap = new unsigned char[lineSize * height]; + if (data) + memcpy(bitmap, data, lineSize * height); +} + +cBitmap::cBitmap(const cBitmap & b) +{ + width = b.width; + height = b.height; + lineSize = b.lineSize; + bitmap = new unsigned char[lineSize * height]; + if (b.bitmap) + memcpy(bitmap, b.bitmap, lineSize * height); +} + +cBitmap::~cBitmap() +{ + delete[] bitmap; +} + +void cBitmap::Clear() +{ + memset(bitmap, 0, lineSize * height); +} + +void cBitmap::Invert() +{ + int i; + + for (i = 0; i < lineSize * height; i++) + { + bitmap[i] ^= 0xFF; + } +} + +void cBitmap::DrawPixel(int x, int y, eColor color) +{ + if (x < 0 || x > width - 1) + return; + if (y < 0 || y > height - 1) + return; + + unsigned char c = 0x80 >> (x % 8); + if (color == clrBlack) + bitmap[lineSize * y + x / 8] |= c; + else + bitmap[lineSize * y + x / 8] &= ~c; +} + +void cBitmap::Draw8Pixels(int x, int y, unsigned char pixels, eColor color) +{ + if (x < 0 || x > width - 1) + return; + if (y < 0 || y > height - 1) + return; + + if (color == clrBlack) + bitmap[lineSize * y + x / 8] |= pixels; + else + bitmap[lineSize * y + x / 8] &= ~pixels; +} + +void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color) +{ + int d, sx, sy, dx, dy; + unsigned int ax, ay; + + dx = x2 - x1; + ax = abs(dx) << 1; + if (dx < 0) + sx = -1; + else + sx = 1; + + dy = y2 - y1; + ay = abs(dy) << 1; + if (dy < 0) + sy = -1; + else + sy = 1; + + DrawPixel(x1, y1, color); + if (ax > ay) + { + d = ay - (ax >> 1); + while (x1 != x2) + { + if (d >= 0) + { + y1 += sy; + d -= ax; + } + x1 += sx; + d += ay; + DrawPixel(x1, y1, color); + } + } + else + { + d = ax - (ay >> 1); + while (y1 != y2) + { + if (d >= 0) + { + x1 += sx; + d -= ay; + } + y1 += sy; + d += ax; + DrawPixel(x1, y1, color); + } + } +} + +void cBitmap::DrawHLine(int x1, int y, int x2, eColor color) +{ + sort(x1,x2); + + if (x1 / 8 == x2 / 8) + { + // start and end in the same byte + Draw8Pixels(x1, y, bitmaskr[x1 % 8] & bitmaskl[x2 % 8], color); + } + else + { + // start and end in different bytes + Draw8Pixels(x1, y, bitmaskr[x1 % 8], color); + x1 = ((x1 + 8) / 8) * 8; + while (x1 < (x2 / 8) * 8) + { + Draw8Pixels(x1, y, 0xff, color); + x1 += 8; + } + Draw8Pixels(x2, y, bitmaskl[x2 % 8], color); + } +} + +void cBitmap::DrawVLine(int x, int y1, int y2, eColor color) +{ + int y; + + sort(y1,y2); + + for (y = y1; y <= y2; y++) + DrawPixel(x, y, color); +} + +void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled) +{ + int y; + + sort(x1,x2); + sort(y1,y2); + + if (!filled) + { + DrawHLine(x1, y1, x2, color); + DrawVLine(x1, y1, y2, color); + DrawHLine(x1, y2, x2, color); + DrawVLine(x2, y1, y2, color); + } + else + { + for (y = y1; y <= y2; y++) + { + DrawHLine(x1, y, x2, color); + } + } +} + +void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int type) +{ + sort(x1,x2); + sort(y1,y2); + + if (type > (x2 - x1) / 2) + type = (x2 - x1) / 2; + if (type > (y2 - y1) / 2) + type = (y2 - y1) / 2; + + if (filled) + { + DrawHLine(x1 + type, y1, x2 - type, color); + for (int y = y1 + 1; y < y1 + type; y++) + DrawHLine(x1 + 1, y, x2 - 1, color); + for (int y = y1 + type; y <= y2 - type; y++) + DrawHLine(x1, y, x2, color); + for (int y = y2 - type + 1; y < y2; y++) + DrawHLine(x1 + 1, y, x2 - 1, color); + DrawHLine(x1 + type, y2, x2 - type, color); + if (type == 4) + { + // round the ugly fat box... + DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); + DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); + DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); + DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); + } + } + else + { + DrawHLine(x1 + type, y1, x2 - type, color); + DrawVLine(x1, y1 + type, y2 - type, color); + DrawVLine(x2, y1 + type, y2 - type, color); + DrawHLine(x1 + type, y2, x2 - type, color); + if (type > 1) + { + DrawHLine(x1 + 1, y1 + 1, x1 + type - 1, color); + DrawHLine(x2 - type + 1, y1 + 1, x2 - 1, color); + DrawHLine(x1 + 1, y2 - 1, x1 + type - 1, color); + DrawHLine(x2 - type + 1, y2 - 1, x2 - 1, color); + DrawVLine(x1 + 1, y1 + 1, y1 + type - 1, color); + DrawVLine(x1 + 1, y2 - 1, y2 - type + 1, color); + DrawVLine(x2 - 1, y1 + 1, y1 + type - 1, color); + DrawVLine(x2 - 1, y2 - 1, y2 - type + 1, color); + } + } +} + +void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants) +{ + // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF + int rx = x2 - x1; + int ry = y2 - y1; + int cx = (x1 + x2) / 2; + int cy = (y1 + y2) / 2; + switch (abs(quadrants)) + { + case 0: rx /= 2; ry /= 2; break; + case 1: cx = x1; cy = y2; break; + case 2: cx = x2; cy = y2; break; + case 3: cx = x2; cy = y1; break; + case 4: cx = x1; cy = y1; break; + case 5: cx = x1; ry /= 2; break; + case 6: cy = y2; rx /= 2; break; + case 7: cx = x2; ry /= 2; break; + case 8: cy = y1; rx /= 2; break; + } + int TwoASquare = 2 * rx * rx; + int TwoBSquare = 2 * ry * ry; + int x = rx; + int y = 0; + int XChange = ry * ry * (1 - 2 * rx); + int YChange = rx * rx; + int EllipseError = 0; + int StoppingX = TwoBSquare * rx; + int StoppingY = 0; + while (StoppingX >= StoppingY) + { + if (filled) + { + switch (quadrants) + { + case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, color, filled); // no break + case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, color, filled); break; + case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, color, filled); // no break + case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, color, filled); break; + case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, color, filled); break; + case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, color, filled); break; + case 0: + case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, color, filled); if (quadrants == 6) break; + case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, color, filled); break; + case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, color, filled); break; + case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, color, filled); break; + case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, color, filled); break; + case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, color, filled); break; + } + } + else + { + switch (quadrants) + { + case 5: DrawPixel(cx + x, cy + y, color); // no break + case -1: + case 1: DrawPixel(cx + x, cy - y, color); break; + case 7: DrawPixel(cx - x, cy + y, color); // no break + case -2: + case 2: DrawPixel(cx - x, cy - y, color); break; + case -3: + case 3: DrawPixel(cx - x, cy + y, color); break; + case -4: + case 4: DrawPixel(cx + x, cy + y, color); break; + case 0: + case 6: DrawPixel(cx - x, cy - y, color); DrawPixel(cx + x, cy - y, color); if (quadrants == 6) break; + case 8: DrawPixel(cx - x, cy + y, color); DrawPixel(cx + x, cy + y, color); break; + } + } + y++; + StoppingY += TwoASquare; + EllipseError += YChange; + YChange += TwoASquare; + if (2 * EllipseError + XChange > 0) + { + x--; + StoppingX -= TwoBSquare; + EllipseError += XChange; + XChange += TwoBSquare; + } + } + x = 0; + y = ry; + XChange = ry * ry; + YChange = rx * rx * (1 - 2 * ry); + EllipseError = 0; + StoppingX = 0; + StoppingY = TwoASquare * ry; + while (StoppingX <= StoppingY) + { + if (filled) + { + switch (quadrants) + { + case 5: DrawRectangle(cx, cy + y, cx + x, cy + y, color, filled); // no break + case 1: DrawRectangle(cx, cy - y, cx + x, cy - y, color, filled); break; + case 7: DrawRectangle(cx - x, cy + y, cx, cy + y, color, filled); // no break + case 2: DrawRectangle(cx - x, cy - y, cx, cy - y, color, filled); break; + case 3: DrawRectangle(cx - x, cy + y, cx, cy + y, color, filled); break; + case 4: DrawRectangle(cx, cy + y, cx + x, cy + y, color, filled); break; + case 0: + case 6: DrawRectangle(cx - x, cy - y, cx + x, cy - y, color, filled); if (quadrants == 6) break; + case 8: DrawRectangle(cx - x, cy + y, cx + x, cy + y, color, filled); break; + case -1: DrawRectangle(cx + x, cy - y, x2, cy - y, color, filled); break; + case -2: DrawRectangle(x1, cy - y, cx - x, cy - y, color, filled); break; + case -3: DrawRectangle(x1, cy + y, cx - x, cy + y, color, filled); break; + case -4: DrawRectangle(cx + x, cy + y, x2, cy + y, color, filled); break; + } + } + else + { + switch (quadrants) + { + case 5: DrawPixel(cx + x, cy + y, color); // no break + case -1: + case 1: DrawPixel(cx + x, cy - y, color); break; + case 7: DrawPixel(cx - x, cy + y, color); // no break + case -2: + case 2: DrawPixel(cx - x, cy - y, color); break; + case -3: + case 3: DrawPixel(cx - x, cy + y, color); break; + case -4: + case 4: DrawPixel(cx + x, cy + y, color); break; + case 0: + case 6: DrawPixel(cx - x, cy - y, color); DrawPixel(cx + x, cy - y, color); if (quadrants == 6) break; + case 8: DrawPixel(cx - x, cy + y, color); DrawPixel(cx + x, cy + y, color); break; + } + } + x++; + StoppingX += TwoBSquare; + EllipseError += XChange; + XChange += TwoBSquare; + if (2 * EllipseError + YChange > 0) + { + y--; + StoppingY -= TwoASquare; + EllipseError += YChange; + YChange += TwoASquare; + } + } +} + +void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type) +{ + bool upper = type & 0x01; + bool falling = type & 0x02; + bool vertical = type & 0x04; + if (vertical) + { + for (int y = y1; y <= y2; y++) + { + double c = cos((y - y1) * M_PI / (y2 - y1 + 1)); + if (falling) + c = -c; + int x = int((x2 - x1 + 1) * c / 2); + if (upper && !falling || !upper && falling) + DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, color, true); + else + DrawRectangle((x1 + x2) / 2 + x, y, x2, y, color, true); + } + } + else + { + for (int x = x1; x <= x2; x++) + { + double c = cos((x - x1) * M_PI / (x2 - x1 + 1)); + if (falling) + c = -c; + int y = int((y2 - y1 + 1) * c / 2); + if (upper) + DrawRectangle(x, y1, x, (y1 + y2) / 2 + y, color, true); + else + DrawRectangle(x, (y1 + y2) / 2 + y, x, y2, color, true); + } + } +} + +void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color) +{ + unsigned char cl = 0; + int xt, yt; + const unsigned char * data = bitmap.Data(); + unsigned short temp; + int h, w; + + w = bitmap.Width(); + h = bitmap.Height(); + + if (data) + { + if (!(x % 8)) + { + // Bitmap is byte alligned (0,8,16,...) + for (yt = 0; yt < h; yt++) + { + for (xt = 0; xt < (w / 8); xt++) + { + cl = *data; + Draw8Pixels(x + (xt * 8), y + yt, cl, color); + data++; + } + if (w % 8) + { + cl = *data; + Draw8Pixels(x + ((w / 8) * 8), y + yt, cl & bitmaskl[w % 8 - 1], color); + data++; + } + } + } + else + { + // Bitmap is not byte alligned + for (yt = 0; yt < h; yt++) + { + temp = 0; + for (xt = 0; xt < (w + (x % 8)) / 8; xt++) + { + cl = *(data + yt * ((w + 7) / 8) + xt); + temp = temp | ((unsigned short) cl << (8 - (x % 8))); + cl = (temp & 0xff00) >> 8; + if (!xt) + { + // first byte + Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl & bitmaskr[x % 8], color); + } + else + { + // not the first byte + Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl, color); + } + temp <<= 8; + } + if ((w + (x % 8) + 7) / 8 != (w + (x % 8)) / 8) + { + // print the rest + cl = *(data + (yt + 1) * ((w + 7) / 8) - 1); + temp = temp | ((unsigned short) cl << (8 - (x % 8))); + cl = (temp & 0xff00) >> 8; + Draw8Pixels(x - (x % 8) + (((w + (x % 8)) / 8) * 8), y + yt, cl & bitmaskl[(w + x) % 8 - 1], color); + } + } + } + } +} + +int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, + eColor color, bool proportional, int skipPixels) +{ + int xt; + int yt; + int i; + char c; + int start; + + clip(x, 0, width - 1); + clip(y, 0, height - 1); + + xt = x; + yt = y; + start = 0; + + if (text.length() > 0) + { + if (skipPixels > 0) + { + if (!proportional) + { + if (skipPixels >= (int) text.length() * font->TotalWidth()) + start = text.length(); + else + while (skipPixels > font->TotalWidth()) + { + skipPixels -= font->TotalWidth(); + start++; + } + } + else + { + if (skipPixels >= font->Width(text)) + start = text.length(); + else + while (skipPixels > font->Width(text[start])) + { + skipPixels -= font->Width(text[start]); + skipPixels -= font->SpaceBetween(); + start++; + } + } + } + for (i = start; i < (int) text.length(); i++) + { + c = text[i]; + if (xt > xmax) + { + i = text.length(); + } + else + { + if (!proportional) + { + if (skipPixels > 0) + { + DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + xt += font->TotalWidth() - skipPixels; + skipPixels = 0; + } + else + { + DrawCharacter(xt, yt, xmax, c, font, color); + xt += font->TotalWidth(); + } + } + else + { + if (skipPixels > 0) + { + xt += DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + skipPixels = 0; + } + else + { + xt += DrawCharacter(xt, yt, xmax, c, font, color); + } + if (xt <= xmax) + { + xt += font->SpaceBetween(); + } + } + } + } + } + return xt; +} + +int cBitmap::DrawCharacter(int x, int y, int xmax, char c, const cFont * font, + eColor color, int skipPixels) +{ + const cBitmap * charBitmap; + + clip(x, 0, width - 1); + clip(y, 0, height - 1); + + charBitmap = font->GetCharacter(c); + if (charBitmap) + { + cBitmap * drawBitmap = charBitmap->SubBitmap(skipPixels, 0, xmax - x + skipPixels, charBitmap->Height() - 1); + if (drawBitmap) + DrawBitmap(x, y, *drawBitmap, color); + delete drawBitmap; + return charBitmap->Width() - skipPixels; + } + return 0; +} + +unsigned char cBitmap::GetPixel(int x, int y) const +{ + unsigned char value; + + value = bitmap[y * lineSize + x / 8]; + value = (value >> (7 - (x % 8))) & 1; + return value; +} + +cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const +{ + int w, h; + int xt, yt; + cBitmap * bmp; + unsigned char cl; + unsigned char * data; + unsigned short temp; + + sort(x1,x2); + sort(y1,y2); + if (x1 < 0 || x1 > width - 1) + return NULL; + if (y1 < 0 || y1 > height - 1) + return NULL; + clip(x2, 0, width - 1); + clip(y2, 0, height - 1); + + w = x2 - x1 + 1; + h = y2 - y1 + 1; + bmp = new cBitmap(w, h); + if (!bmp || !bmp->Data()) + return NULL; + bmp->Clear(); + if (x1 % 8 == 0) + { + // Bitmap is byte alligned (0,8,16,...) + for (yt = 0; yt < h; yt++) + { + data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; + for (xt = 0; xt < (w / 8) * 8; xt += 8) + { + cl = *data; + bmp->Draw8Pixels(xt, yt, cl, clrBlack); + data++; + } + if (w % 8 != 0) + { + cl = *data; + bmp->Draw8Pixels(xt, yt, cl & bitmaskl[w % 8 - 1], clrBlack); + } + } + } + else + { + // Bitmap is not byte alligned + for (yt = 0; yt < h; yt++) + { + temp = 0; + data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; + for (xt = 0; xt <= ((w / 8)) * 8; xt += 8) + { + cl = *data; + temp = temp | ((unsigned short) cl << (x1 % 8)); + cl = (temp & 0xff00) >> 8; + if (xt > 0) + { + bmp->Draw8Pixels(xt - 8, yt, cl, clrBlack); + } + temp <<= 8; + data++; + } + if (w % 8 != 0) + { + // print the rest + if (8 - (x1 % 8) < w % 8) + { + cl = *data; + temp = temp | ((unsigned short) cl << (x1 % 8)); + } + cl = (temp & 0xff00) >> 8; + bmp->Draw8Pixels(xt - 8, yt, cl & bitmaskl[(w % 8) - 1], clrBlack); + } + } + } + return bmp; +} + +bool cBitmap::LoadPBM(const std::string & fileName) +{ + FILE * pbmFile; + char str[32]; + int i; + int ch; + int w; + int h; + + pbmFile = fopen(fileName.c_str(), "rb"); + if (!pbmFile) + return false; + + i = 0; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + if (strcmp(str, "P4") != 0) + return false; + + while ((ch = getc(pbmFile)) == '#') + { + while ((ch = getc(pbmFile)) != EOF) + { + if (ch == '\n' || ch == '\r') + break; + } + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + i = 0; + str[i] = ch; + i += 1; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + w = atoi(str); + + i = 0; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + h = atoi(str); + + delete[] bitmap; + width = w; + height = h; + // lines are byte aligned + lineSize = (width + 7) / 8; + bitmap = new unsigned char[lineSize * height]; + fread(bitmap, lineSize * height, 1, pbmFile); + fclose(pbmFile); + + return true; +} + +void cBitmap::SavePBM(const std::string & fileName) +{ + int i; + char str[32]; + FILE * fp; + + fp = fopen(fileName.c_str(), "wb"); + if (fp) + { + sprintf(str, "P4\n%d %d\n", width, height); + fwrite(str, strlen(str), 1, fp); + for (i = 0; i < lineSize * height; i++) + { + fwrite(&bitmap[i], 1, 1, fp); + } + fclose(fp); + } +} + +} // end of namespace diff --git a/glcdgraphics/bitmap.h b/glcdgraphics/bitmap.h new file mode 100644 index 0000000..b6446a0 --- /dev/null +++ b/glcdgraphics/bitmap.h @@ -0,0 +1,75 @@ +/* + * GraphLCD graphics library + * + * bitmap.h - cBitmap class + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_BITMAP_H_ +#define _GLCDGRAPHICS_BITMAP_H_ + +#include <string> + +namespace GLCD +{ + +enum eColor +{ + clrBlack, + clrWhite +}; + +class cFont; + +class cBitmap +{ +protected: + int width; + int height; + int lineSize; + unsigned char * bitmap; + +public: + cBitmap(int width, int height, unsigned char * data = NULL); + cBitmap(const cBitmap & b); + ~cBitmap(); + + int Width() const { return width; } + int Height() const { return height; } + int LineSize() const { return lineSize; } + const unsigned char * Data() const { return bitmap; } + + void Clear(); + void Invert(); + void DrawPixel(int x, int y, eColor color); + void Draw8Pixels(int x, int y, unsigned char pixels, eColor color); + void DrawLine(int x1, int y1, int x2, int y2, eColor color); + void DrawHLine(int x1, int y, int x2, eColor color); + void DrawVLine(int x, int y1, int y2, eColor color); + void DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled); + void DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int size); + void DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants); + void DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type); + void DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color); + int DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, + eColor color = clrBlack, bool proportional = true, int skipPixels = 0); + int DrawCharacter(int x, int y, int xmax, char c, const cFont * font, + eColor color = clrBlack, int skipPixels = 0); + + cBitmap * SubBitmap(int x1, int y1, int x2, int y2) const; + unsigned char GetPixel(int x, int y) const; + + bool LoadPBM(const std::string & fileName); + void SavePBM(const std::string & fileName); +}; + +} // end of namespace + +#endif diff --git a/glcdgraphics/common.c b/glcdgraphics/common.c new file mode 100644 index 0000000..8942424 --- /dev/null +++ b/glcdgraphics/common.c @@ -0,0 +1,60 @@ +/* + * GraphLCD graphics library + * + * common.c - various functions + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include <ctype.h> + +#include "common.h" + + +namespace GLCD +{ + +void clip(int & value, int min, int max) +{ + if (value < min) + value = min; + if (value > max) + value = max; +} + +void sort(int & value1, int & value2) +{ + if (value2 < value1) + { + int tmp; + tmp = value2; + value2 = value1; + value1 = tmp; + } +} + +std::string trim(const std::string & s) +{ + std::string::size_type start, end; + + start = 0; + while (start < s.length()) + { + if (!isspace(s[start])) + break; + start++; + } + end = s.length() - 1; + while (end >= 0) + { + if (!isspace(s[end])) + break; + end--; + } + return s.substr(start, end - start + 1); +} + +} // end of namespace diff --git a/glcdgraphics/common.h b/glcdgraphics/common.h new file mode 100644 index 0000000..2865602 --- /dev/null +++ b/glcdgraphics/common.h @@ -0,0 +1,26 @@ +/* + * GraphLCD graphics library + * + * common.h - various functions + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_COMMON_H_ +#define _GLCDGRAPHICS_COMMON_H_ + +#include <string> + +namespace GLCD +{ + +void clip(int & value, int min, int max); +void sort(int & value1, int & value2); +std::string trim(const std::string & s); + +} // end of namespace + +#endif diff --git a/glcdgraphics/font.c b/glcdgraphics/font.c new file mode 100644 index 0000000..1735cf2 --- /dev/null +++ b/glcdgraphics/font.c @@ -0,0 +1,581 @@ +/* + * GraphLCD graphics library + * + * font.c - font handling + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include <stdio.h> +#include <stdint.h> +#include <syslog.h> +#include <fcntl.h> +#include <unistd.h> + +#include <algorithm> + +#include "common.h" +#include "font.h" + +#ifdef HAVE_FREETYPE2 +#include <ft2build.h> +#include FT_FREETYPE_H +#include <iconv.h> +#endif + +namespace GLCD +{ + +static const char * kFontFileSign = "FNT3"; +static const uint32_t kFontHeaderSize = 16; +static const uint32_t kCharHeaderSize = 4; + +//#pragma pack(1) +//struct tFontHeader +//{ +// char sign[4]; // = FONTFILE_SIGN +// unsigned short height; // total height of the font +// unsigned short ascent; // ascender of the font +// unsigned short line; // line height +// unsigned short reserved; +// unsigned short space; // space between characters of a string +// unsigned short count; // number of chars in this file +//}; +// +//struct tCharHeader +//{ +// unsigned short character; +// unsigned short width; +//}; +//#pragma pack() + +cFont::cFont() +{ + Init(); +} + +cFont::~cFont() +{ + Unload(); +} + +bool cFont::LoadFNT(const std::string & fileName) +{ + // cleanup if we already had a loaded font + Unload(); + + FILE * fontFile; + int i; + uint8_t buffer[10000]; + uint16_t fontHeight; + uint16_t numChars; + int maxWidth = 0; + + fontFile = fopen(fileName.c_str(), "rb"); + if (!fontFile) + return false; + + fread(buffer, kFontHeaderSize, 1, fontFile); + if (buffer[0] != kFontFileSign[0] || + buffer[1] != kFontFileSign[1] || + buffer[2] != kFontFileSign[2] || + buffer[3] != kFontFileSign[3]) + { + fclose(fontFile); + return false; + } + + fontHeight = buffer[4] | (buffer[5] << 8); + totalAscent = buffer[6] | (buffer[7] << 8); + lineHeight = buffer[8] | (buffer[9] << 8); + spaceBetween = buffer[12] | (buffer[13] << 8); + numChars = buffer[14] | (buffer[15] << 8); + for (i = 0; i < numChars; i++) + { + uint8_t chdr[kCharHeaderSize]; + uint16_t charWidth; + uint16_t character; + fread(chdr, kCharHeaderSize, 1, fontFile); + character = chdr[0] | (chdr[1] << 8); + charWidth = chdr[2] | (chdr[3] << 8); + fread(buffer, fontHeight * ((charWidth + 7) / 8), 1, fontFile); + if (characters[character]) + delete characters[character]; + characters[character] = new cBitmap(charWidth, fontHeight, buffer); + if (characters[character]->Width() > maxWidth) + maxWidth = characters[character]->Width(); + } + fclose(fontFile); + + totalWidth = maxWidth; + totalHeight = fontHeight; + + return true; +} + +bool cFont::SaveFNT(const std::string & fileName) const +{ + FILE * fontFile; + uint8_t fhdr[kFontHeaderSize]; + uint8_t chdr[kCharHeaderSize]; + uint16_t numChars; + int i; + + fontFile = fopen(fileName.c_str(),"w+b"); + if (!fontFile) + { + syslog(LOG_ERR, "cFont::SaveFNT(): Cannot open file: %s for writing\n",fileName.c_str()); + return false; + } + + numChars = 0; + for (i = 0; i < 256; i++) + { + if (characters[i]) + { + numChars++; + } + } + + memcpy(fhdr, kFontFileSign, 4); + fhdr[4] = (uint8_t) totalHeight; + fhdr[5] = (uint8_t) (totalHeight >> 8); + fhdr[6] = (uint8_t) totalAscent; + fhdr[7] = (uint8_t) (totalAscent >> 8); + fhdr[8] = (uint8_t) lineHeight; + fhdr[9] = (uint8_t) (lineHeight >> 8); + fhdr[10] = 0; + fhdr[11] = 0; + fhdr[12] = (uint8_t) spaceBetween; + fhdr[13] = (uint8_t) (spaceBetween >> 8); + fhdr[14] = (uint8_t) numChars; + fhdr[15] = (uint8_t) (numChars >> 8); + + // write font file header + fwrite(fhdr, kFontHeaderSize, 1, fontFile); + + for (i = 0; i < 256; i++) + { + if (characters[i]) + { + chdr[0] = (uint8_t) i; + chdr[1] = (uint8_t) (i >> 8); + chdr[2] = (uint8_t) characters[i]->Width(); + chdr[3] = (uint8_t) (characters[i]->Width() >> 8); + fwrite(chdr, kCharHeaderSize, 1, fontFile); + fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile); + } + } + + fclose(fontFile); + + syslog(LOG_DEBUG, "cFont::SaveFNT(): Font file '%s' written successfully\n", fileName.c_str()); + + return true; +} + +bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, + int size, bool dingBats) +{ + // cleanup if we already had a loaded font + Unload(); +#ifdef HAVE_FREETYPE2 + if (access(fileName.c_str(), F_OK) != 0) + { + syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) does not exist!!", fileName.c_str()); + return false; + } + // file exists + FT_Library library; + FT_Face face; + FT_GlyphSlot slot; + + int error = FT_Init_FreeType(&library); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: Could not init freetype library"); + return false; + } + error = FT_New_Face(library, fileName.c_str(), 0, &face); + // everything ok? + if (error == FT_Err_Unknown_File_Format) + { + syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) could be opened and read, but it appears that its font format is unsupported", fileName.c_str()); + error = FT_Done_Face(face); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); + error = FT_Done_FreeType(library); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); + return false; + } + else if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: Font file (%s) could not be opened or read, or simply it is broken,\n error code was %x", fileName.c_str(), error); + error = FT_Done_Face(face); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); + error = FT_Done_FreeType(library); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); + return false; + } + + // set slot + slot = face->glyph; + + // set Size + FT_Set_Char_Size(face, 0, size * 64, 0, 0); + + wchar_t utf_buff[256]; + if (dingBats) + { +/* + FT_CharMap charmap = 0; + for (int n = 0; n < face->num_charmaps; n++) + { + if (face->charmaps[n]->platform_id == 3 && + face->charmaps[n]->encoding_id == 0) + { + charmap = face->charmaps[n]; + //break; + } + } + if (charmap) + syslog(LOG_ERR, "cFont::LoadFT2: platform_id: %d, encoding_id: %d", charmap->platform_id, charmap->encoding_id); + error = FT_Set_Charmap(_face, charmap); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: FT_Select_Charmap encoding not supported: %d", charmap->encoding_id); + } +*/ + } + else + { + iconv_t cd; + if ((cd = iconv_open("WCHAR_T", encoding.c_str())) == (iconv_t) -1) + { + syslog(LOG_ERR, "cFont::LoadFT2: Iconv encoding not supported: %s", encoding.c_str()); + error = FT_Done_Face(face); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); + error = FT_Done_FreeType(library); + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); + return false; + } + for (int c = 0; c < 256; c++) + { + char char_buff = c; + wchar_t wchar_buff; + char * in_buff,* out_buff; + size_t in_len, out_len, count; + + in_len = 1; + out_len = 4; + in_buff = (char *) &char_buff; + out_buff = (char *) &wchar_buff; + count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len); + if ((size_t) -1 == count) + { + utf_buff[c] = 0; + } + utf_buff[c] = wchar_buff; + } + iconv_close(cd); + } + + // get some global parameters + totalHeight = (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6); + totalWidth = face->size->metrics.max_advance >> 6; + totalAscent = face->size->metrics.ascender >> 6; + lineHeight = face->size->metrics.height >> 6; + spaceBetween = 0; +#if 0 + syslog(LOG_DEBUG, "cFont::LoadFT2: totalHeight = %d", totalHeight); + syslog(LOG_DEBUG, "cFont::LoadFT2: totalWidth = %d", totalWidth); + syslog(LOG_DEBUG, "cFont::LoadFT2: totalAscent = %d", totalAscent); + syslog(LOG_DEBUG, "cFont::LoadFT2: lineHeight = %d", lineHeight); + syslog(LOG_DEBUG, "cFont::LoadFT2: spaceBetween = %d", spaceBetween); +#endif + // render glyphs for ASCII codes 0 to 255 in our bitmap class + FT_UInt glyph_index; + int num_char; + + for (num_char = 0; num_char < 256; num_char++) + { + if (dingBats) + { + //Get FT char index & load the char + error = FT_Load_Char(face, num_char, FT_LOAD_DEFAULT); + } + else + { + //Get FT char index + glyph_index = FT_Get_Char_Index(face, utf_buff[num_char]); + //Load the char + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + } + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error); + } + + // convert to a mono bitmap + error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error); + } + + // now, fill our pixel data + cBitmap * charBitmap = new cBitmap(face->glyph->advance.x >> 6, totalHeight); + charBitmap->Clear(); + unsigned char * bufPtr = face->glyph->bitmap.buffer; + unsigned char pixel; + for (int y = 0; y < face->glyph->bitmap.rows; y++) + { + for (int x = 0; x < face->glyph->bitmap.width; x++) + { + pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1; + if (pixel) + charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, + (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, + GLCD::clrBlack); + } + bufPtr += face->glyph->bitmap.pitch; + } + SetCharacter((char) num_char, charBitmap); + } + error = FT_Done_Face(face); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); + } + error = FT_Done_FreeType(library); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); + } + return true; +#else + syslog(LOG_ERR, "cFont::LoadFT2: glcdgraphics was compiled without FreeType2 support!!!"); + return false; +#endif +} + +int cFont::Width(char ch) const +{ + if (characters[(unsigned char) ch]) + return characters[(unsigned char) ch]->Width(); + else + return 0; +} + +int cFont::Width(const std::string & str) const +{ + unsigned int i; + int sum = 0; + + for (i = 0; i < str.length(); i++) + { + sum += Width(str[i]); + } + if (str.length() > 1) + { + sum += spaceBetween * (str.length() - 1); + } + return sum; +} + +int cFont::Width(const std::string & str, unsigned int len) const +{ + unsigned int i; + int sum = 0; + + for (i = 0; i < str.length() && i < len; i++) + { + sum += Width(str[i]); + } + if (std::min(str.length(), (size_t) len) > 1) + { + sum += spaceBetween * (std::min(str.length(), (size_t) len) - 1); + } + return sum; +} + +int cFont::Height(char ch) const +{ + if (characters[(unsigned char) ch]) + return characters[(unsigned char) ch]->Height(); + else + return 0; +} + +int cFont::Height(const std::string & str) const +{ + unsigned int i; + int sum = 0; + + for (i = 0; i < str.length(); i++) + sum = std::max(sum, Height(str[i])); + return sum; +} + +int cFont::Height(const std::string & str, unsigned int len) const +{ + unsigned int i; + int sum = 0; + + for (i = 0; i < str.length() && i < len; i++) + sum = std::max(sum, Height(str[i])); + return sum; +} + +const cBitmap * cFont::GetCharacter(char ch) const +{ + return characters[(unsigned char) ch]; +} + +void cFont::SetCharacter(char ch, cBitmap * bitmapChar) +{ + // adjust maxwidth if necessary + if (totalWidth < bitmapChar->Width()) + totalWidth = bitmapChar->Width(); + + // delete if already allocated + if (characters[(unsigned char) ch]) + delete characters[(unsigned char) ch]; + + // store new character + characters[(unsigned char) ch] = bitmapChar; +} + +void cFont::Init() +{ + totalWidth = 0; + totalHeight = 0; + totalAscent = 0; + spaceBetween = 0; + lineHeight = 0; + for (int i = 0; i < 256; i++) + { + characters[i] = NULL; + } +} + +void cFont::Unload() +{ + // cleanup + for (int i = 0; i < 256; i++) + { + if (characters[i]) + { + delete characters[i]; + } + } + // re-init + Init(); +} + +void cFont::WrapText(int Width, int Height, std::string & Text, + std::vector <std::string> & Lines, int * ActualWidth) const +{ + int maxLines; + int lineCount; + int textWidth; + std::string::size_type start; + std::string::size_type pos; + std::string::size_type posLast; + + Lines.clear(); + maxLines = 2000; + if (Height > 0) + { + maxLines = Height / LineHeight(); + if (maxLines == 0) + maxLines = 1; + } + lineCount = 0; + + pos = 0; + start = 0; + posLast = 0; + textWidth = 0; + while (pos < Text.length() && (Height == 0 || lineCount < maxLines)) + { + if (Text[pos] == '\n') + { + Lines.push_back(trim(Text.substr(start, pos - start))); + start = pos + 1; + posLast = pos + 1; + textWidth = 0; + lineCount++; + } + else if (textWidth > Width && (lineCount + 1) < maxLines) + { + if (posLast > start) + { + Lines.push_back(trim(Text.substr(start, posLast - start))); + start = posLast + 1; + posLast = start; + textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; + } + else + { + Lines.push_back(trim(Text.substr(start, pos - start))); + start = pos + 1; + posLast = start; + textWidth = this->Width(Text[pos]) + spaceBetween; + } + lineCount++; + } + else if (Text[pos] == ' ') + { + posLast = pos; + textWidth += this->Width(Text[pos]) + spaceBetween; + } + else + { + textWidth += this->Width(Text[pos]) + spaceBetween; + } + pos++; + } + + if (Height == 0 || lineCount < maxLines) + { + if (textWidth > Width && (lineCount + 1) < maxLines) + { + if (posLast > start) + { + Lines.push_back(trim(Text.substr(start, posLast - start))); + start = posLast + 1; + posLast = start; + textWidth = this->Width(Text.substr(start, pos - start + 1)) + spaceBetween; + } + else + { + Lines.push_back(trim(Text.substr(start, pos - start))); + start = pos + 1; + posLast = start; + textWidth = this->Width(Text[pos]) + spaceBetween; + } + lineCount++; + } + if (pos > start) + { + Lines.push_back(trim(Text.substr(start))); + lineCount++; + } + textWidth = 0; + for (int i = 0; i < lineCount; i++) + textWidth = std::max(textWidth, this->Width(Lines[i])); + textWidth = std::min(textWidth, Width); + } + else + textWidth = Width; + if (ActualWidth) + *ActualWidth = textWidth; +} + +} // end of namespace diff --git a/glcdgraphics/font.h b/glcdgraphics/font.h new file mode 100644 index 0000000..b36d5ac --- /dev/null +++ b/glcdgraphics/font.h @@ -0,0 +1,75 @@ +/* + * GraphLCD graphics library + * + * font.h - font handling + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_FONT_H_ +#define _GLCDGRAPHICS_FONT_H_ + +#include <string> +#include <vector> + +#include "bitmap.h" + +namespace GLCD +{ + +class cFont +{ +private: + int totalWidth; + int totalHeight; + int totalAscent; + int spaceBetween; + int lineHeight; + + cBitmap * characters[256]; +protected: + void Init(); + void Unload(); +public: + cFont(); + ~cFont(); + + bool LoadFNT(const std::string & fileName); + bool SaveFNT(const std::string & fileName) const; + bool LoadFT2(const std::string & fileName, const std::string & encoding, + int size, bool dingBats = false); + int TotalWidth() const { return totalWidth; }; + int TotalHeight() const { return totalHeight; }; + int TotalAscent() const { return totalAscent; }; + int SpaceBetween() const { return spaceBetween; }; + int LineHeight() const { return lineHeight; }; + + void SetTotalWidth(int width) { totalWidth = width; }; + void SetTotalHeight(int height) { totalHeight = height; }; + void SetTotalAscent(int ascent) { totalAscent = ascent; }; + void SetSpaceBetween(int width) { spaceBetween = width; }; + void SetLineHeight(int height) { lineHeight = height; }; + + int Width(char ch) const; + int Width(const std::string & str) const; + int Width(const std::string & str, unsigned int len) const; + int Height(char ch) const; + int Height(const std::string & str) const; + int Height(const std::string & str, unsigned int len) const; + + const cBitmap * GetCharacter(char ch) const; + void SetCharacter(char ch, cBitmap * bitmapChar); + + void WrapText(int Width, int Height, std::string & Text, + std::vector <std::string> & Lines, int * TextWidth = NULL) const; +}; + +} // end of namespace + +#endif diff --git a/glcdgraphics/glcd.c b/glcdgraphics/glcd.c new file mode 100644 index 0000000..6a74c33 --- /dev/null +++ b/glcdgraphics/glcd.c @@ -0,0 +1,277 @@ +/* + * GraphLCD graphics library + * + * glcd.c - GLCD file loading and saving + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include <stdio.h> +#include <stdint.h> +#include <syslog.h> + +#include <string> + +#include "bitmap.h" +#include "glcd.h" +#include "image.h" + + +namespace GLCD +{ + +using namespace std; + +const char * kGLCDFileSign = "GLC"; + +/* +#pragma pack(1) +struct tGLCDHeader +{ + char sign[3]; // = "GLC" + char format; // D - single image, A - animation + uint16_t width; // width in pixels + uint16_t height; // height in pixels + // only for animations + uint16_t count; // number of pictures + uint32_t delay; // delay in ms +}; +#pragma pack() +*/ + +cGLCDFile::cGLCDFile() +{ +} + +cGLCDFile::~cGLCDFile() +{ +} + +bool cGLCDFile::Load(cImage & image, const string & fileName) +{ + FILE * fp; + long fileSize; + char sign[4]; + uint8_t buf[6]; + uint16_t width; + uint16_t height; + uint16_t count; + uint32_t delay; + + fp = fopen(fileName.c_str(), "rb"); + if (!fp) + { + syslog(LOG_ERR, "glcdgraphics: open %s failed (cGLCDFile::Load).", fileName.c_str()); + return false; + } + + // get len of file + if (fseek(fp, 0, SEEK_END) != 0) + { + fclose(fp); + return false; + } + fileSize = ftell(fp); + + // rewind and get Header + if (fseek(fp, 0, SEEK_SET) != 0) + { + fclose(fp); + return false; + } + + // read header sign + if (fread(sign, 4, 1, fp) != 1) + { + fclose(fp); + return false; + } + + // check header sign + if (strncmp(sign, kGLCDFileSign, 3) != 0) + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + + // read width and height + if (fread(buf, 4, 1, fp) != 1) + { + fclose(fp); + return false; + } + + width = (buf[1] << 8) | buf[0]; + height = (buf[3] << 8) | buf[2]; + if (width == 0 || height == 0) + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + + if (sign[3] == 'D') + { + count = 1; + delay = 10; + // check file length + if (fileSize != (long) (height * ((width + 7) / 8) + 8)) + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong size (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + } + else if (sign[3] == 'A') + { + // read count and delay + if (fread(buf, 6, 1, fp) != 1) + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + count = (buf[1] << 8) | buf[0]; + delay = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; + // check file length + if (count == 0 || + fileSize != (long) (count * (height * ((width + 7) / 8)) + 14)) + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong size (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + // Set minimal limit for next image + if (delay < 10) + delay = 10; + } + else + { + syslog(LOG_ERR, "glcdgraphics: load %s failed, wrong header (cGLCDFile::Load).", fileName.c_str()); + fclose(fp); + return false; + } + + image.Clear(); + image.SetWidth(width); + image.SetHeight(height); + image.SetDelay(delay); + unsigned char * bmpdata = new unsigned char[height * ((width + 7) / 8)]; + if (bmpdata) + { + for (unsigned int n = 0; n < count; n++) + { + if (fread(bmpdata, height * ((width + 7) / 8), 1, fp) != 1) + { + delete[] bmpdata; + fclose(fp); + image.Clear(); + return false; + } + image.AddBitmap(new cBitmap(width, height, bmpdata)); + } + delete[] bmpdata; + } + else + { + syslog(LOG_ERR, "glcdgraphics: malloc failed (cGLCDFile::Load)."); + fclose(fp); + image.Clear(); + return false; + } + fclose(fp); + + syslog(LOG_DEBUG, "glcdgraphics: image %s loaded.", fileName.c_str()); + return true; +} + +bool cGLCDFile::Save(cImage & image, const string & fileName) +{ + FILE * fp; + uint8_t buf[14]; + uint16_t width; + uint16_t height; + uint16_t count; + uint32_t delay; + const cBitmap * bitmap; + int i; + + if (image.Count() == 0) + return false; + + fp = fopen(fileName.c_str(), "wb"); + if (!fp) + { + syslog(LOG_ERR, "glcdgraphics: open %s failed (cGLCDFile::Save).", fileName.c_str()); + return false; + } + + memcpy(buf, kGLCDFileSign, 3); + count = image.Count(); + delay = image.Delay(); + if (count == 1) + { + buf[3] = 'D'; + } + else + { + buf[3] = 'A'; + } + bitmap = image.GetBitmap(0); + width = bitmap->Width(); + height = bitmap->Height(); + buf[4] = (uint8_t) width; + buf[5] = (uint8_t) (width >> 8); + buf[6] = (uint8_t) height; + buf[7] = (uint8_t) (height >> 8); + if (count == 1) + { + if (fwrite(buf, 8, 1, fp) != 1) + { + fclose(fp); + return false; + } + } + else + { + buf[8] = (uint8_t) count; + buf[9] = (uint8_t) (count >> 8); + buf[10] = (uint8_t) delay; + buf[11] = (uint8_t) (delay >> 8); + buf[12] = (uint8_t) (delay >> 16); + buf[13] = (uint8_t) (delay >> 24); + if (fwrite(buf, 14, 1, fp) != 1) + { + fclose(fp); + return false; + } + } + for (i = 0; i < count; i++) + { + bitmap = image.GetBitmap(i); + if (bitmap) + { + if (bitmap->Width() == width && bitmap->Height() == height) + { + if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1) + { + fclose(fp); + return false; + } + } + } + } + fclose(fp); + + syslog(LOG_DEBUG, "glcdgraphics: image %s saved.", fileName.c_str()); + return true; +} + +} // end of namespace diff --git a/glcdgraphics/glcd.h b/glcdgraphics/glcd.h new file mode 100644 index 0000000..7f811aa --- /dev/null +++ b/glcdgraphics/glcd.h @@ -0,0 +1,36 @@ +/* + * GraphLCD graphics library + * + * glcd.h - GLCD file loading and saving + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_GLCD_H_ +#define _GLCDGRAPHICS_GLCD_H_ + +#include "imagefile.h" + +namespace GLCD +{ + +class cImage; + +class cGLCDFile : public cImageFile +{ +public: + cGLCDFile(); + virtual ~cGLCDFile(); + virtual bool Load(cImage & image, const std::string & fileName); + virtual bool Save(cImage & image, const std::string & fileName); +}; + +} // end of namespace + +#endif diff --git a/glcdgraphics/image.c b/glcdgraphics/image.c new file mode 100644 index 0000000..72003b1 --- /dev/null +++ b/glcdgraphics/image.c @@ -0,0 +1,67 @@ +/* + * GraphLCD graphics library + * + * image.c - image and animation handling + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include "bitmap.h" +#include "image.h" + + +namespace GLCD +{ + +using namespace std; + +cImage::cImage() +: width(0), + height(0), + delay(0), + curBitmap(0), + lastChange(0) +{ +} + +cImage::~cImage() +{ + Clear(); +} + +cBitmap * cImage::GetBitmap() const +{ + if (curBitmap < bitmaps.size()) + return bitmaps[curBitmap]; + return NULL; +} + +cBitmap * cImage::GetBitmap(unsigned int nr) const +{ + if (nr < bitmaps.size()) + return bitmaps[nr]; + return NULL; +} + +void cImage::Clear() +{ + vector <cBitmap *>::iterator it; + for (it = bitmaps.begin(); it != bitmaps.end(); it++) + { + delete *it; + } + bitmaps.clear(); + width = 0; + height = 0; + delay = 0; + curBitmap = 0; + lastChange = 0; +} + +} // end of namespace diff --git a/glcdgraphics/image.h b/glcdgraphics/image.h new file mode 100644 index 0000000..888d942 --- /dev/null +++ b/glcdgraphics/image.h @@ -0,0 +1,58 @@ +/* + * GraphLCD graphics library + * + * image.h - image and animation handling + * + * based on graphlcd plugin 0.1.1 for the Video Disc Recorder + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_IMAGE_H_ +#define _GLCDGRAPHICS_IMAGE_H_ + +#include <stdint.h> + +#include <vector> + +namespace GLCD +{ + +class cBitmap; + +class cImage +{ +private: + unsigned int width; + unsigned int height; + unsigned int delay; + unsigned int curBitmap; + uint64_t lastChange; + std::vector <cBitmap *> bitmaps; +public: + cImage(); + ~cImage(); + + unsigned int Width() const { return width; } + unsigned int Height() const { return height; } + unsigned int Count() const { return bitmaps.size(); } + unsigned int Delay() const { return delay; } + uint64_t LastChange() const { return lastChange; } + void First(uint64_t t) { lastChange = t; curBitmap = 0; } + bool Next(uint64_t t) { lastChange = t; curBitmap++; return curBitmap < bitmaps.size(); } + void SetWidth(unsigned int Width) { width = Width; } + void SetHeight(unsigned int Height) { height = Height; } + void SetDelay(unsigned int d) { delay = d; } + cBitmap * GetBitmap(unsigned int nr) const; + cBitmap * GetBitmap() const; + void AddBitmap(cBitmap * Bitmap) { bitmaps.push_back(Bitmap); } + void Clear(); +}; + +} // end of namespace + +#endif diff --git a/glcdgraphics/imagefile.c b/glcdgraphics/imagefile.c new file mode 100644 index 0000000..2f56f4a --- /dev/null +++ b/glcdgraphics/imagefile.c @@ -0,0 +1,35 @@ +/* + * GraphLCD graphics library + * + * imagefile.h - base class for file loading and saving + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2006 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include "image.h" +#include "imagefile.h" + +namespace GLCD +{ + +cImageFile::cImageFile(void) +{ +} +cImageFile::~cImageFile(void) +{ +} + +bool cImageFile::Load(cImage & image, const std::string & fileName) +{ + return false; +} + +bool cImageFile::Save(cImage & image, const std::string & fileName) +{ + return false; +} + +} // end of namespace diff --git a/glcdgraphics/imagefile.h b/glcdgraphics/imagefile.h new file mode 100644 index 0000000..bf5ff5e --- /dev/null +++ b/glcdgraphics/imagefile.h @@ -0,0 +1,33 @@ +/* + * GraphLCD graphics library + * + * imagefile.h - base class for file loading and saving + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2006 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_IMAGEFILE_H_ +#define _GLCDGRAPHICS_IMAGEFILE_H_ + +#include <string> + +namespace GLCD +{ + +class cImage; + +class cImageFile +{ +public: + cImageFile(); + virtual ~cImageFile(); + virtual bool Load(cImage & image, const std::string & fileName); + virtual bool Save(cImage & image, const std::string & fileName); +}; + +} // end of namespace + +#endif diff --git a/glcdgraphics/pbm.c b/glcdgraphics/pbm.c new file mode 100644 index 0000000..fe60104 --- /dev/null +++ b/glcdgraphics/pbm.c @@ -0,0 +1,187 @@ +/* + * GraphLCD graphics library + * + * pbm.c - PBM file loading and saving + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2006 Andreas Regel <andreas.regel AT powarman.de> + */ + +#include <stdio.h> +#include <stdint.h> +#include <syslog.h> + +#include <string> + +#include "bitmap.h" +#include "pbm.h" +#include "image.h" + + +namespace GLCD +{ + +cPBMFile::cPBMFile() +{ +} + +cPBMFile::~cPBMFile() +{ +} + +bool cPBMFile::Load(cImage & image, const std::string & fileName) +{ + FILE * pbmFile; + char str[32]; + int i; + int ch; + int w; + int h; + + pbmFile = fopen(fileName.c_str(), "rb"); + if (!pbmFile) + return false; + + i = 0; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + if (strcmp(str, "P4") != 0) + return false; + + while ((ch = getc(pbmFile)) == '#') + { + while ((ch = getc(pbmFile)) != EOF) + { + if (ch == '\n' || ch == '\r') + break; + } + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + i = 0; + str[i] = ch; + i += 1; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + w = atoi(str); + + i = 0; + while ((ch = getc(pbmFile)) != EOF && i < 31) + { + if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') + break; + str[i] = ch; + i++; + } + if (ch == EOF) + { + fclose(pbmFile); + return false; + } + str[i] = 0; + h = atoi(str); + + image.Clear(); + image.SetWidth(w); + image.SetHeight(h); + image.SetDelay(100); + unsigned char * bmpdata = new unsigned char[h * ((w + 7) / 8)]; + if (bmpdata) + { + if (fread(bmpdata, h * ((w + 7) / 8), 1, pbmFile) != 1) + { + delete[] bmpdata; + fclose(pbmFile); + image.Clear(); + return false; + } + image.AddBitmap(new cBitmap(w, h, bmpdata)); + delete[] bmpdata; + } + else + { + syslog(LOG_ERR, "glcdgraphics: malloc failed (cPBMFile::Load)."); + fclose(pbmFile); + return false; + } + fclose(pbmFile); + syslog(LOG_DEBUG, "glcdgraphics: image %s loaded.", fileName.c_str()); + + return true; +} + +bool cPBMFile::Save(cImage & image, const std::string & fileName) +{ + FILE * fp; + char str[32]; + const cBitmap * bitmap; + + if (image.Count() == 1) + { + fp = fopen(fileName.c_str(), "wb"); + if (fp) + { + bitmap = image.GetBitmap(0); + if (bitmap) + { + sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); + fwrite(str, strlen(str), 1, fp); + fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + } + fclose(fp); + } + } + else + { + uint16_t i; + char tmpStr[256]; + + for (i = 0; i < image.Count(); i++) + { + sprintf(tmpStr, "%.248s.%05d", fileName.c_str(), i); + fp = fopen(tmpStr, "wb"); + if (fp) + { + bitmap = image.GetBitmap(i); + if (bitmap) + { + sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); + fwrite(str, strlen(str), 1, fp); + fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + } + fclose(fp); + } + } + } + return true; +} + +} // end of namespace + diff --git a/glcdgraphics/pbm.h b/glcdgraphics/pbm.h new file mode 100644 index 0000000..8e9535f --- /dev/null +++ b/glcdgraphics/pbm.h @@ -0,0 +1,34 @@ +/* + * GraphLCD graphics library + * + * pbm.h - PBM file loading and saving + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2006 Andreas Regel <andreas.regel AT powarman.de> + */ + +#ifndef _GLCDGRAPHICS_PBM_H_ +#define _GLCDGRAPHICS_PBM_H_ + +#include "imagefile.h" + +namespace GLCD +{ + +class cImage; + +class cPBMFile : public cImageFile +{ +public: + cPBMFile(); + virtual ~cPBMFile(); + virtual bool Load(cImage & image, const std::string & fileName); + virtual bool Save(cImage & image, const std::string & fileName); +}; + +} // end of namespace + +#endif + |