summaryrefslogtreecommitdiff
path: root/utils/wpseditor/screenshot
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2008-09-03 20:51:13 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2008-09-03 20:51:13 +0000
commitc1c1383e235a85d504f476b25c0b41bbfe8d927c (patch)
treeb3332b66c3ddd95f74c214ee1aec56997a1279d2 /utils/wpseditor/screenshot
parent4f26222a9f3cfe4d52f04785807df95e75c32d86 (diff)
* WPS editor: set eol-style
* Add CLI-only screenshot utility (using libwps) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18402 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/wpseditor/screenshot')
-rw-r--r--utils/wpseditor/screenshot/Makefile43
-rw-r--r--utils/wpseditor/screenshot/bmp.h114
-rw-r--r--utils/wpseditor/screenshot/gd_bmp.c778
-rw-r--r--utils/wpseditor/screenshot/main.c361
4 files changed, 1296 insertions, 0 deletions
diff --git a/utils/wpseditor/screenshot/Makefile b/utils/wpseditor/screenshot/Makefile
new file mode 100644
index 0000000000..18a6de35a5
--- /dev/null
+++ b/utils/wpseditor/screenshot/Makefile
@@ -0,0 +1,43 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id$
+#
+ROOT=../../..
+
+OS = w32
+CC = gcc
+
+ifeq ($(findstring MINGW,$(shell uname)),MINGW)
+OS = w32
+CC = mingw32-gcc
+RM = rm
+endif
+
+ifeq ($(findstring Linux,$(shell uname)),Linux)
+OS = linux
+CC = gcc
+RM = rm -f
+endif
+
+
+
+COMMON= main.c gd_bmp.c
+
+INCLUDE=-I ../libwps/src \
+ -I $(ROOT)/apps/gui \
+ -I $(ROOT)/firmware/export \
+ -I $(ROOT)/apps/recorder \
+ -I $(ROOT)/apps \
+ -I .
+
+CFLAGS = -g -Wall
+
+all:
+ $(CC) $(INCLUDE) $(CFLAGS) $(COMMON) -rdynamic -ldl -lgd -lpng -o screenshot
+
+clean:
+ $(RM) screenshot
diff --git a/utils/wpseditor/screenshot/bmp.h b/utils/wpseditor/screenshot/bmp.h
new file mode 100644
index 0000000000..71d5a4a5bc
--- /dev/null
+++ b/utils/wpseditor/screenshot/bmp.h
@@ -0,0 +1,114 @@
+/* $Id$ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ gd_bmp.c
+
+ Bitmap format support for libgd
+
+ * Written 2007, Scott MacVicar
+ ---------------------------------------------------------------------------
+
+ Todo:
+
+ RLE4, RLE8 and Bitfield encoding
+ Add full support for Windows v4 and Windows v5 header formats
+
+ ----------------------------------------------------------------------------
+ */
+
+#ifndef BMP_H
+#define BMP_H 1
+
+#define BMP_PALETTE_3 1
+#define BMP_PALETTE_4 2
+
+#define BMP_WINDOWS_V3 40
+#define BMP_OS2_V1 12
+#define BMP_OS2_V2 64
+#define BMP_WINDOWS_V4 108
+#define BMP_WINDOWS_V5 124
+
+#define BMP_BI_RGB 0
+#define BMP_BI_RLE8 1
+#define BMP_BI_RLE4 2
+#define BMP_BI_BITFIELDS 3
+#define BMP_BI_JPEG 4
+#define BMP_BI_PNG 5
+
+#define BMP_RLE_COMMAND 0
+#define BMP_RLE_ENDOFLINE 0
+#define BMP_RLE_ENDOFBITMAP 1
+#define BMP_RLE_DELTA 2
+
+#define BMP_RLE_TYPE_RAW 0
+#define BMP_RLE_TYPE_RLE 1
+
+/* BMP header. */
+typedef struct
+{
+ /* 16 bit - header identifying the type */
+ signed short int magic;
+
+ /* 32bit - size of the file */
+ int size;
+
+ /* 16bit - these two are in the spec but "reserved" */
+ signed short int reserved1;
+ signed short int reserved2;
+
+ /* 32 bit - offset of the bitmap header from data in bytes */
+ signed int off;
+
+} bmp_hdr_t;
+
+/* BMP info. */
+typedef struct
+{
+ /* 16bit - Type, ie Windows or OS/2 for the palette info */
+ signed short int type;
+ /* 32bit - The length of the bitmap information header in bytes. */
+ signed int len;
+
+ /* 32bit - The width of the bitmap in pixels. */
+ signed int width;
+
+ /* 32bit - The height of the bitmap in pixels. */
+ signed int height;
+
+ /* 8 bit - The bitmap data is specified in top-down order. */
+ signed char topdown;
+
+ /* 16 bit - The number of planes. This must be set to a value of one. */
+ signed short int numplanes;
+
+ /* 16 bit - The number of bits per pixel. */
+ signed short int depth;
+
+ /* 32bit - The type of compression used. */
+ signed int enctype;
+
+ /* 32bit - The size of the image in bytes. */
+ signed int size;
+
+ /* 32bit - The horizontal resolution in pixels/metre. */
+ signed int hres;
+
+ /* 32bit - The vertical resolution in pixels/metre. */
+ signed int vres;
+
+ /* 32bit - The number of color indices used by the bitmap. */
+ signed int numcolors;
+
+ /* 32bit - The number of color indices important for displaying the bitmap. */
+ signed int mincolors;
+
+} bmp_info_t;
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/utils/wpseditor/screenshot/gd_bmp.c b/utils/wpseditor/screenshot/gd_bmp.c
new file mode 100644
index 0000000000..8fe737da03
--- /dev/null
+++ b/utils/wpseditor/screenshot/gd_bmp.c
@@ -0,0 +1,778 @@
+/*
+ Stolen from http://cvs.php.net/viewcvs.cgi/gd/playground/gdbmp/
+*/
+
+/*
+ gd_bmp.c
+
+ Bitmap format support for libgd
+
+ * Written 2007, Scott MacVicar
+ ---------------------------------------------------------------------------
+
+ Todo:
+
+ Bitfield encoding
+
+ ----------------------------------------------------------------------------
+ */
+/* $Id$ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include "gd.h"
+#include "bmp.h"
+
+extern void* gdCalloc (size_t nmemb, size_t size);
+
+static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
+static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
+static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
+static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
+static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
+
+static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
+static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
+static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
+static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
+static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
+
+#if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
+/* Byte helper functions, since added to GD 2.1 */
+static int gdGetIntLSB(signed int *result, gdIOCtx * ctx);
+static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx);
+#endif
+
+#define BMP_DEBUG(s)
+
+gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile);
+
+gdImagePtr gdImageCreateFromBmp(FILE * inFile)
+{
+ gdImagePtr im = 0;
+ gdIOCtx *in = gdNewFileCtx(inFile);
+ im = gdImageCreateFromBmpCtx(in);
+ in->gd_free(in);
+ return im;
+}
+
+gdImagePtr gdImageCreateFromBmpPtr(int size, void *data)
+{
+ gdImagePtr im;
+ gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
+ im = gdImageCreateFromBmpCtx(in);
+ in->gd_free(in);
+ return im;
+}
+
+gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
+{
+ bmp_hdr_t *hdr;
+ bmp_info_t *info;
+ gdImagePtr im = NULL;
+ int error = 0;
+
+ if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
+ return NULL;
+ }
+
+ if (bmp_read_header(infile, hdr)) {
+ gdFree(hdr);
+ return NULL;
+ }
+
+ if (hdr->magic != 0x4d42) {
+ gdFree(hdr);
+ return NULL;
+ }
+
+ if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
+ gdFree(hdr);
+ return NULL;
+ }
+
+ if (bmp_read_info(infile, info)) {
+ gdFree(hdr);
+ gdFree(info);
+ return NULL;
+ }
+
+ BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
+ BMP_DEBUG(printf("Width: %d\n", info->width));
+ BMP_DEBUG(printf("Height: %d\n", info->height));
+ BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
+ BMP_DEBUG(printf("Depth: %d\n", info->depth));
+ BMP_DEBUG(printf("Offset: %d\n", hdr->off));
+
+ if (info->depth >= 16) {
+ im = gdImageCreateTrueColor(info->width, info->height);
+ } else {
+ im = gdImageCreate(info->width, info->height);
+ }
+
+ if (!im) {
+ gdFree(hdr);
+ gdFree(info);
+ return NULL;
+ }
+
+ switch (info->depth) {
+ case 1:
+ BMP_DEBUG(printf("1-bit image\n"));
+ error = bmp_read_1bit(im, infile, info, hdr);
+ break;
+ case 4:
+ BMP_DEBUG(printf("4-bit image\n"));
+ error = bmp_read_4bit(im, infile, info, hdr);
+ break;
+ case 8:
+ BMP_DEBUG(printf("8-bit image\n"));
+ error = bmp_read_8bit(im, infile, info, hdr);
+ break;
+ case 16:
+ case 24:
+ case 32:
+ BMP_DEBUG(printf("Direct BMP image\n"));
+ error = bmp_read_direct(im, infile, info, hdr);
+ break;
+ default:
+ BMP_DEBUG(printf("Unknown bit count\n"));
+ error = 1;
+ }
+
+ gdFree(hdr);
+ gdFree(info);
+
+ if (error) {
+ gdImageDestroy(im);
+ return NULL;
+ }
+
+ return im;
+}
+
+static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
+{
+ if(
+ !gdGetWordLSB(&hdr->magic, infile) ||
+ !gdGetIntLSB(&hdr->size, infile) ||
+ !gdGetWordLSB(&hdr->reserved1, infile) ||
+ !gdGetWordLSB(&hdr->reserved2 , infile) ||
+ !gdGetIntLSB(&hdr->off , infile)
+ ) {
+ return 1;
+ }
+ return 0;
+}
+
+static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
+{
+ /* read BMP length so we can work out the version */
+ if (!gdGetIntLSB(&info->len, infile)) {
+ return 1;
+ }
+
+ switch (info->len) {
+ /* For now treat Windows v4 + v5 as v3 */
+ case BMP_WINDOWS_V3:
+ case BMP_WINDOWS_V4:
+ case BMP_WINDOWS_V5:
+ BMP_DEBUG(printf("Reading Windows Header\n"));
+ if (bmp_read_windows_v3_info(infile, info)) {
+ return 1;
+ }
+ break;
+ case BMP_OS2_V1:
+ if (bmp_read_os2_v1_info(infile, info)) {
+ return 1;
+ }
+ break;
+ case BMP_OS2_V2:
+ if (bmp_read_os2_v2_info(infile, info)) {
+ return 1;
+ }
+ break;
+ default:
+ BMP_DEBUG(printf("Unhandled bitmap\n"));
+ return 1;
+ }
+ return 0;
+}
+
+static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
+{
+ if (
+ !gdGetIntLSB(&info->width, infile) ||
+ !gdGetIntLSB(&info->height, infile) ||
+ !gdGetWordLSB(&info->numplanes, infile) ||
+ !gdGetWordLSB(&info->depth, infile) ||
+ !gdGetIntLSB(&info->enctype, infile) ||
+ !gdGetIntLSB(&info->size, infile) ||
+ !gdGetIntLSB(&info->hres, infile) ||
+ !gdGetIntLSB(&info->vres, infile) ||
+ !gdGetIntLSB(&info->numcolors, infile) ||
+ !gdGetIntLSB(&info->mincolors, infile)
+ ) {
+ return 1;
+ }
+
+ if (info->height < 0) {
+ info->topdown = 1;
+ info->height = -info->height;
+ } else {
+ info->topdown = 0;
+ }
+
+ info->type = BMP_PALETTE_4;
+
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
+ info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
+{
+ if (
+ !gdGetWordLSB((signed short int *)&info->width, infile) ||
+ !gdGetWordLSB((signed short int *)&info->height, infile) ||
+ !gdGetWordLSB(&info->numplanes, infile) ||
+ !gdGetWordLSB(&info->depth, infile)
+ ) {
+ return 1;
+ }
+
+ /* OS2 v1 doesn't support topdown */
+ info->topdown = 0;
+
+ info->numcolors = 1 << info->depth;
+ info->type = BMP_PALETTE_3;
+
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
+ info->depth <= 0 || info->numcolors < 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
+{
+ char useless_bytes[24];
+ if (
+ !gdGetIntLSB(&info->width, infile) ||
+ !gdGetIntLSB(&info->height, infile) ||
+ !gdGetWordLSB(&info->numplanes, infile) ||
+ !gdGetWordLSB(&info->depth, infile) ||
+ !gdGetIntLSB(&info->enctype, infile) ||
+ !gdGetIntLSB(&info->size, infile) ||
+ !gdGetIntLSB(&info->hres, infile) ||
+ !gdGetIntLSB(&info->vres, infile) ||
+ !gdGetIntLSB(&info->numcolors, infile) ||
+ !gdGetIntLSB(&info->mincolors, infile)
+ ) {
+ return 1;
+ }
+
+ /* Lets seek the next 24 pointless bytes, we don't care too much about it */
+ if (!gdGetBuf(useless_bytes, 24, infile)) {
+ return 1;
+ }
+
+ if (info->height < 0) {
+ info->topdown = 1;
+ info->height = -info->height;
+ } else {
+ info->topdown = 0;
+ }
+
+ info->type = BMP_PALETTE_4;
+
+ if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
+ info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
+ return 1;
+ }
+
+
+ return 0;
+}
+
+static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
+{
+ int ypos = 0, xpos = 0, row = 0;
+ int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
+ signed short int data = 0;
+
+ switch(info->enctype) {
+ case BMP_BI_RGB:
+ /* no-op */
+ break;
+
+ case BMP_BI_BITFIELDS:
+ if (info->depth == 24) {
+ BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
+ return 1;
+ }
+ BMP_DEBUG(printf("Currently no bitfield support\n"));
+ return 1;
+ break;
+
+ case BMP_BI_RLE8:
+ if (info->depth != 8) {
+ BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
+ return 1;
+ }
+ case BMP_BI_RLE4:
+ if (info->depth != 4) {
+ BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
+ return 1;
+ }
+ case BMP_BI_JPEG:
+ case BMP_BI_PNG:
+ default:
+ BMP_DEBUG(printf("Unsupported BMP compression format\n"));
+ return 1;
+ }
+
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
+ if (gdTell(infile) != header->off) {
+ /* Should make sure we don't seek past the file size */
+ gdSeek(infile, header->off);
+ }
+
+ /* The line must be divisible by 4, else its padded with NULLs */
+ padding = ((int)(info->depth / 8) * info->width) % 4;
+ if (padding) {
+ padding = 4 - padding;
+ }
+
+
+ for (ypos = 0; ypos < info->height; ++ypos) {
+ if (info->topdown) {
+ row = ypos;
+ } else {
+ row = info->height - ypos - 1;
+ }
+
+ for (xpos = 0; xpos < info->width; xpos++) {
+ if (info->depth == 16) {
+ if (!gdGetWordLSB(&data, infile)) {
+ return 1;
+ }
+ BMP_DEBUG(printf("Data: %X\n", data));
+ red = ((data & 0x7C00) >> 10) << 3;
+ green = ((data & 0x3E0) >> 5) << 3;
+ blue = (data & 0x1F) << 3;
+ BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
+ } else if (info->depth == 24) {
+ if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
+ return 1;
+ }
+ } else {
+ if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
+ return 1;
+ }
+ }
+ /*alpha = gdAlphaMax - (alpha >> 1);*/
+ gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
+ }
+ for (xpos = padding; xpos > 0; --xpos) {
+ if (!gdGetByte(&red, infile)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
+{
+ int i;
+ int r, g, b, z;
+
+ for (i = 0; i < count; i++) {
+ if (
+ !gdGetByte(&r, infile) ||
+ !gdGetByte(&g, infile) ||
+ !gdGetByte(&b, infile) ||
+ (read_four && !gdGetByte(&z, infile))
+ ) {
+ return 1;
+ }
+ im->red[i] = r;
+ im->green[i] = g;
+ im->blue[i] = b;
+ im->open[i] = 1;
+ }
+ return 0;
+}
+
+static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
+{
+ int ypos = 0, xpos = 0, row = 0, index = 0;
+ int padding = 0, current_byte = 0, bit = 0;
+
+ if (info->enctype != BMP_BI_RGB) {
+ return 1;
+ }
+
+ if (!info->numcolors) {
+ info->numcolors = 2;
+ } else if (info->numcolors < 0 || info->numcolors > 2) {
+ return 1;
+ }
+
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
+ return 1;
+ }
+
+ im->colorsTotal = info->numcolors;
+
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
+ if (gdTell(infile) != header->off) {
+ /* Should make sure we don't seek past the file size */
+ gdSeek(infile, header->off);
+ }
+
+ /* The line must be divisible by 4, else its padded with NULLs */
+ padding = ((int)ceill(0.1 * info->width)) % 4;
+ if (padding) {
+ padding = 4 - padding;
+ }
+
+ for (ypos = 0; ypos < info->height; ++ypos) {
+ if (info->topdown) {
+ row = ypos;
+ } else {
+ row = info->height - ypos - 1;
+ }
+
+ for (xpos = 0; xpos < info->width; xpos += 8) {
+ /* Bitmaps are always aligned in bytes so we'll never overflow */
+ if (!gdGetByte(&current_byte, infile)) {
+ return 1;
+ }
+
+ for (bit = 0; bit < 8; bit++) {
+ index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
+ if (im->open[index]) {
+ im->open[index] = 0;
+ }
+ gdImageSetPixel(im, xpos + bit, row, index);
+ /* No need to read anything extra */
+ if ((xpos + bit) >= info->width) {
+ break;
+ }
+ }
+ }
+
+ for (xpos = padding; xpos > 0; --xpos) {
+ if (!gdGetByte(&index, infile)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
+{
+ int ypos = 0, xpos = 0, row = 0, index = 0;
+ int padding = 0, current_byte = 0;
+
+ if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
+ return 1;
+ }
+
+ if (!info->numcolors) {
+ info->numcolors = 16;
+ } else if (info->numcolors < 0 || info->numcolors > 16) {
+ return 1;
+ }
+
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
+ return 1;
+ }
+
+ im->colorsTotal = info->numcolors;
+
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
+ if (gdTell(infile) != header->off) {
+ /* Should make sure we don't seek past the file size */
+ gdSeek(infile, header->off);
+ }
+
+ /* The line must be divisible by 4, else its padded with NULLs */
+ padding = ((int)ceil(0.5 * info->width)) % 4;
+ if (padding) {
+ padding = 4 - padding;
+ }
+
+ switch (info->enctype) {
+ case BMP_BI_RGB:
+ for (ypos = 0; ypos < info->height; ++ypos) {
+ if (info->topdown) {
+ row = ypos;
+ } else {
+ row = info->height - ypos - 1;
+ }
+
+ for (xpos = 0; xpos < info->width; xpos += 2) {
+ if (!gdGetByte(&current_byte, infile)) {
+ return 1;
+ }
+
+ index = (current_byte >> 4) & 0x0f;
+ if (im->open[index]) {
+ im->open[index] = 0;
+ }
+ gdImageSetPixel(im, xpos, row, index);
+
+ /* This condition may get called often, potential optimsations */
+ if (xpos >= info->width) {
+ break;
+ }
+
+ index = current_byte & 0x0f;
+ if (im->open[index]) {
+ im->open[index] = 0;
+ }
+ gdImageSetPixel(im, xpos + 1, row, index);
+ }
+
+ for (xpos = padding; xpos > 0; --xpos) {
+ if (!gdGetByte(&index, infile)) {
+ return 1;
+ }
+ }
+ }
+ break;
+
+ case BMP_BI_RLE4:
+ if (bmp_read_rle(im, infile, info)) {
+ return 1;
+ }
+ break;
+
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
+{
+ int ypos = 0, xpos = 0, row = 0, index = 0;
+ int padding = 0;
+
+ if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
+ return 1;
+ }
+
+ if (!info->numcolors) {
+ info->numcolors = 256;
+ } else if (info->numcolors < 0 || info->numcolors > 256) {
+ return 1;
+ }
+
+ if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
+ return 1;
+ }
+
+ im->colorsTotal = info->numcolors;
+
+ /* There is a chance the data isn't until later, would be wierd but it is possible */
+ if (gdTell(infile) != header->off) {
+ /* Should make sure we don't seek past the file size */
+ gdSeek(infile, header->off);
+ }
+
+ /* The line must be divisible by 4, else its padded with NULLs */
+ padding = (1 * info->width) % 4;
+ if (padding) {
+ padding = 4 - padding;
+ }
+
+ switch (info->enctype) {
+ case BMP_BI_RGB:
+ for (ypos = 0; ypos < info->height; ++ypos) {
+ if (info->topdown) {
+ row = ypos;
+ } else {
+ row = info->height - ypos - 1;
+ }
+
+ for (xpos = 0; xpos < info->width; ++xpos) {
+ if (!gdGetByte(&index, infile)) {
+ return 1;
+ }
+
+ if (im->open[index]) {
+ im->open[index] = 0;
+ }
+ gdImageSetPixel(im, xpos, row, index);
+ }
+ /* Could create a new variable, but it isn't really worth it */
+ for (xpos = padding; xpos > 0; --xpos) {
+ if (!gdGetByte(&index, infile)) {
+ return 1;
+ }
+ }
+ }
+ break;
+
+ case BMP_BI_RLE8:
+ if (bmp_read_rle(im, infile, info)) {
+ return 1;
+ }
+ break;
+
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
+{
+ int ypos = 0, xpos = 0, row = 0, index = 0;
+ int rle_length = 0, rle_data = 0;
+ int padding = 0;
+ int i = 0, j = 0;
+ int pixels_per_byte = 8 / info->depth;
+
+ for (ypos = 0; ypos < info->height && xpos <= info->width;) {
+ if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
+ return 1;
+ }
+ row = info->height - ypos - 1;
+
+ if (rle_length != BMP_RLE_COMMAND) {
+ if (im->open[rle_data]) {
+ im->open[rle_data] = 0;
+ }
+
+ for (i = 0; (i < rle_length) && (xpos < info->width);) {
+ for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
+ index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
+ if (im->open[index]) {
+ im->open[index] = 0;
+ }
+ gdImageSetPixel(im, xpos, row, index);
+ }
+ }
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
+ /* Uncompressed RLE needs to be even */
+ padding = 0;
+ for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
+ int max_pixels = pixels_per_byte;
+
+ if (!gdGetByte(&index, infile)) {
+ return 1;
+ }
+ padding++;
+
+ if (rle_data - i < max_pixels) {
+ max_pixels = rle_data - i;
+ }
+
+ for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
+ int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
+ if (im->open[temp]) {
+ im->open[temp] = 0;
+ }
+ gdImageSetPixel(im, xpos, row, temp);
+ }
+ }
+
+ /* Make sure the bytes read are even */
+ if (padding % 2 && !gdGetByte(&index, infile)) {
+ return 1;
+ }
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
+ /* Next Line */
+ xpos = 0;
+ ypos++;
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
+ /* Delta Record, used for bmp files that contain other data*/
+ if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
+ return 1;
+ }
+ xpos += rle_length;
+ ypos += rle_data;
+ } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
+ /* End of bitmap */
+ break;
+ }
+ }
+ return 0;
+}
+
+#if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
+static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx)
+{
+ unsigned int high = 0, low = 0;
+ low = (ctx->getC) (ctx);
+ if (low == EOF) {
+ return 0;
+ }
+
+ high = (ctx->getC) (ctx);
+ if (high == EOF) {
+ return 0;
+ }
+
+ if (result) {
+ *result = (high << 8) | low;
+ }
+
+ return 1;
+}
+
+static int gdGetIntLSB(signed int *result, gdIOCtx * ctx)
+{
+ int c = 0;
+ unsigned int r = 0;
+
+ c = (ctx->getC) (ctx);
+ if (c == EOF) {
+ return 0;
+ }
+ r |= (c << 24);
+ r >>= 8;
+
+ c = (ctx->getC) (ctx);
+ if (c == EOF) {
+ return 0;
+ }
+ r |= (c << 24);
+ r >>= 8;
+
+ c = (ctx->getC) (ctx);
+ if (c == EOF) {
+ return 0;
+ }
+ r |= (c << 24);
+ r >>= 8;
+
+ c = (ctx->getC) (ctx);
+ if (c == EOF) {
+ return 0;
+ }
+ r |= (c << 24);
+
+ if (result) {
+ *result = (signed int)r;
+ }
+
+ return 1;
+}
+#endif
diff --git a/utils/wpseditor/screenshot/main.c b/utils/wpseditor/screenshot/main.c
new file mode 100644
index 0000000000..fb81e069b0
--- /dev/null
+++ b/utils/wpseditor/screenshot/main.c
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2008 by Maurus Cuelenaere
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include "gd.h"
+#include "gdfonts.h"
+#include "api.h"
+
+#define DEBUGF1 _debug
+#define DEBUGF2 if(verbose) _debug
+
+#define getFont() gdFontGetSmall()
+
+static struct trackstate mp3data =
+{
+(char*)"Test title",
+(char*)"Test artist",
+(char*)"Test album",
+(char*)"Test genre",
+(char*)"Test disc",
+(char*)"Test track",
+(char*)"Test year",
+(char*)"Test composer",
+(char*)"Test comment",
+(char*)"Test album artist",
+(char*)"Test grouping",
+1, /* int discnum */
+1, /* int tracknum */
+1, /* int version */
+1, /* int layer */
+2008, /* int year */
+
+100, /* int length */
+70 /* int elapsed */
+};
+
+static struct wpsstate wpsdata = {-20, -1, -1, 70, API_STATUS_FASTFORWARD};
+ /* volume, fontheight, fontwidth, battery_level, audio_status */
+
+static struct proxy_api api;
+static bool verbose = false;
+static int (*wps_init)(const char* buff, struct proxy_api *api, bool isfile);
+static int (*wps_display)();
+static int (*wps_refresh)();
+static gdImagePtr framebuffer;
+static gdImagePtr backdrop;
+
+extern gdImagePtr gdImageCreateFromBmp(FILE * inFile);
+extern char *get_current_dir_name (void) __THROW;
+
+int _debug(const char* fmt,...)
+{
+#if 0 /* Doesn't want to compile ?? */
+ struct va_list ap;
+
+ va_start(ap, fmt);
+
+ fprintf(stdout, "[DBG] ");
+ vfprintf(stdout, fmt, ap);
+ fprintf(stdout, "\n");
+
+ va_end(ap);
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+void _putsxy(int x, int y, const unsigned char *str)
+{
+ struct viewport_api avp;
+ int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
+
+ api.get_current_vp(&avp);
+
+ gdImageString(framebuffer, getFont(), x + avp.x, y + avp.y - avp.fontheight, (unsigned char*)str, black);
+}
+
+void _transparent_bitmap_part(const void *src, int src_x, int src_y,
+ int stride, int x, int y, int width, int height)
+{
+ FILE *_image;
+ gdImagePtr image;
+ int pink;
+
+ DEBUGF2("transparent_bitmap_part(const void *src=%s, int src_x=%d, int src_y=%d, int stride=%d, int x=%d, int y=%d, int width=%d, int height=%d", (char*)src, src_x, src_y, stride, x, y, width, height);
+
+ _image = fopen(src, "rb");
+ if(_image == NULL)
+ return;
+
+ image = gdImageCreateFromBmp(_image);
+ fclose(_image);
+
+ pink = gdTrueColor(255, 0, 255);
+ gdImageColorTransparent(image, pink);
+
+ gdImageCopy(framebuffer, image, x, y, src_x, src_y, width, height);
+
+ gdImageDestroy(image);
+}
+
+void _bitmap_part(const void *src, int src_x, int src_y,
+ int stride, int x, int y, int width, int height)
+{
+ FILE *_image;
+ gdImagePtr image;
+
+ DEBUGF2("bitmap_part(const void *src=%s, int src_x=%d, int src_y=%d, int stride=%d, int x=%d, int y=%d, int width=%d, int height=%d", (char*)src, src_x, src_y, stride, x, y, width, height);
+
+ _image = fopen(src, "rb");
+ if(_image == NULL)
+ return;
+
+ image = gdImageCreateFromBmp(_image);
+ fclose(_image);
+
+ gdImageCopy(framebuffer, image, x, y, src_x, src_y, width, height);
+
+ gdImageDestroy(image);
+}
+
+void _drawpixel(int x, int y)
+{
+ int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
+ gdImageSetPixel(framebuffer, x, y, black);
+}
+
+void _fillrect(int x, int y, int width, int height)
+{
+ /* Don't draw this as backdrop is used */
+#if 0
+ int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
+ gdImageFilledRectangle(framebuffer, x, y, x+width, y+height, black);
+#endif
+}
+
+void _hline(int x1, int x2, int y)
+{
+ int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
+ gdImageLine(framebuffer, x1, y, x2, y, black);
+}
+
+void _vline(int x, int y1, int y2)
+{
+ int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
+ gdImageLine(framebuffer, x, y1, x, y2, black);
+}
+
+void _clear_viewport(int x, int y, int w, int h, int color)
+{
+ if(backdrop == NULL)
+ return;
+
+ gdImageCopy(framebuffer, backdrop, x, y, x, y, w, h);
+}
+
+static bool _load_wps_backdrop(char* filename)
+{
+ FILE *image;
+ if(backdrop != NULL)
+ gdImageDestroy(backdrop);
+
+ DEBUGF2("load backdrop: %s", filename);
+
+ image = fopen(filename, "rb");
+ if(image == NULL)
+ return false;
+
+ backdrop = gdImageCreateFromBmp(image);
+ fclose(image);
+
+ return true;
+}
+
+int _read_bmp_file(const char* filename, int *width, int *height)
+{
+ FILE *_image;
+ gdImagePtr image;
+
+ DEBUGF2("load backdrop: %s", filename);
+
+ _image = fopen(filename, "rb");
+ if(_image == NULL)
+ return 0;
+
+ image = gdImageCreateFromBmp(_image);
+ fclose(_image);
+
+ *width = image->sx;
+ *height = image->sy;
+
+ gdImageDestroy(image);
+
+ return 1;
+}
+
+static void _drawBackdrop()
+{
+ if(backdrop == NULL)
+ return;
+
+ gdImageCopy(framebuffer, backdrop, 0, 0, 0, 0, backdrop->sx, backdrop->sy);
+}
+
+static int screenshot(char *model, char *wps, char *png)
+{
+ char lib[255];
+ void *handle;
+ FILE *out, *in;
+
+ in = fopen(wps, "rb");
+ if(in == NULL)
+ {
+ fprintf(stderr, "[ERR] Cannot open WPS: %s\n", wps);
+ return -1;
+ }
+ fclose(in);
+
+ out = fopen(png, "wb");
+ if(out == NULL)
+ {
+ fprintf(stderr, "[ERR] Cannot open PNG: %s\n", png);
+ return -2;
+ }
+
+ snprintf(lib, 255, "%s/libwps_%s.so", (char*)get_current_dir_name(), (char*)model);
+ handle = dlopen(lib, RTLD_LAZY);
+ if (!handle)
+ {
+ fprintf(stderr, "[ERR] Cannot open library: %s\n", dlerror());
+ fclose(out);
+ return -3;
+ }
+
+ wps_init = dlsym(handle, "wps_init");
+ wps_display = dlsym(handle, "wps_display");
+ wps_refresh = dlsym(handle, "wps_refresh");
+
+ if (!wps_init || !wps_display || !wps_refresh)
+ {
+ fprintf(stderr, "[ERR] Failed to resolve funcs!");
+ dlclose(handle);
+ fclose(out);
+ return -4;
+ }
+
+ memset(&api, 0, sizeof(struct proxy_api));
+
+ if(verbose)
+ api.verbose = 3;
+ else
+ api.verbose = 0;
+
+ api.putsxy = &_putsxy;
+ api.transparent_bitmap_part = &_transparent_bitmap_part;
+ api.bitmap_part = &_bitmap_part;
+ api.drawpixel = &_drawpixel;
+ api.fillrect = &_fillrect;
+ api.hline = &_hline;
+ api.vline = &_vline;
+ api.clear_viewport = &_clear_viewport;
+ api.load_wps_backdrop = &_load_wps_backdrop;
+ api.read_bmp_file = &_read_bmp_file;
+ api.debugf = &_debug;
+
+ wps_init(wps, &api, true);
+
+ framebuffer = gdImageCreateTrueColor(api.getwidth(), api.getheight());
+
+ _drawBackdrop();
+
+ if(strcmp(api.get_model_name(), model) != 0)
+ {
+ fprintf(stderr, "[ERR] Model name doesn't match the one supplied by the library\n");
+ fprintf(stderr, " %s <-> %s\n", model, api.get_model_name());
+ dlclose(handle);
+ fclose(out);
+ gdImageDestroy(framebuffer);
+ gdImageDestroy(backdrop);
+ wps_init = NULL;
+ wps_display = NULL;
+ wps_refresh = NULL;
+ return -5;
+ }
+ fprintf(stdout, "[INFO] Model: %s\n", api.get_model_name());
+
+ wpsdata.fontheight = getFont()->h;
+ wpsdata.fontwidth = getFont()->w;
+ api.set_wpsstate(wpsdata);
+ api.set_trackstate(mp3data);
+ api.set_next_trackstate(mp3data);
+
+ _drawBackdrop();
+ wps_refresh();
+ gdImagePng(framebuffer, out);
+
+ fprintf(stdout, "[INFO] Image written\n");
+
+ dlclose(handle);
+ fclose(out);
+ gdImageDestroy(framebuffer);
+ gdImageDestroy(backdrop);
+
+ wps_init = NULL;
+ wps_display = NULL;
+ wps_refresh = NULL;
+
+ return 0;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: screenshot [-V] <MODEL> <WPS_FILE> <OUT_PNG>\n");
+ fprintf(stderr, "Example: screenshot h10_5gb iCatcher.wps out.png\n");
+}
+
+int main(int argc, char ** argv)
+{
+ if(argc < 4)
+ {
+ usage();
+ return -1;
+ }
+
+ if(strcmp(argv[1], "-V") == 0)
+ {
+ verbose = true;
+ return screenshot(argv[2], argv[3], argv[4]);
+ }
+ else
+ {
+ verbose = false;
+ return screenshot(argv[1], argv[2], argv[3]);
+ }
+
+ return 0;
+}