diff options
author | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-09-03 20:51:13 +0000 |
---|---|---|
committer | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-09-03 20:51:13 +0000 |
commit | c1c1383e235a85d504f476b25c0b41bbfe8d927c (patch) | |
tree | b3332b66c3ddd95f74c214ee1aec56997a1279d2 /utils/wpseditor/screenshot | |
parent | 4f26222a9f3cfe4d52f04785807df95e75c32d86 (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/Makefile | 43 | ||||
-rw-r--r-- | utils/wpseditor/screenshot/bmp.h | 114 | ||||
-rw-r--r-- | utils/wpseditor/screenshot/gd_bmp.c | 778 | ||||
-rw-r--r-- | utils/wpseditor/screenshot/main.c | 361 |
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(¤t_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(¤t_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; +} |