/*************************************************************************** * __________ __ ___. * 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 #include #include #include #include #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; static bool next_nl = false; int _debug(const char* fmt,...) { va_list ap; va_start(ap, fmt); if(!next_nl) fprintf(stdout, "[DBG] "); vfprintf(stdout, fmt, ap); if(fmt[strlen(fmt)-1] != 0xa) next_nl = true; else next_nl = false; va_end(ap); return 0; } 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\n", (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\n", (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; int res; 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; res = wps_init(wps, &api, true); if(res != 1) { fprintf(stderr, "[ERR] WPS wasn't correctly inited\n"); dlclose(handle); fclose(out); return -5; } framebuffer = gdImageCreateTrueColor(api.getwidth(), api.getheight()); _drawBackdrop(); 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); if(backdrop != NULL) gdImageDestroy(backdrop); wps_init = NULL; wps_display = NULL; wps_refresh = NULL; return 0; } static void usage(void) { fprintf(stderr, "Rockbox WPS screenshot utility\n"); fprintf(stderr, "Made by Maurus Cuelenaere\n"); fprintf(stderr, "\n"); fprintf(stderr, "Usage: screenshot [-V] .png\n"); fprintf(stderr, " -> creates a PNG screenshot of the WPS for the specific MODEL\n"); fprintf(stderr, " -> libwps_.so must be present in the same directory\n"); fprintf(stderr, " -> -V sets verbose mode ON\n"); fprintf(stderr, "\n"); fprintf(stderr, "Example: screenshot IRIVER_H10_5GB iCatcher.wps out.png\n"); } int main(int argc, char ** argv) { if(argc < 4) { usage(); return -1; } if(argv[1] == NULL || argv[2] == NULL || argv[3] == NULL || (strcmp(argv[1], "-V") == 0 && argv[4] == NULL) ) { 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; }