summaryrefslogtreecommitdiff
path: root/utils/wpseditor/screenshot
diff options
context:
space:
mode:
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 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9ROOT=../../..
10
11OS = w32
12CC = gcc
13
14ifeq ($(findstring MINGW,$(shell uname)),MINGW)
15OS = w32
16CC = mingw32-gcc
17RM = rm
18endif
19
20ifeq ($(findstring Linux,$(shell uname)),Linux)
21OS = linux
22CC = gcc
23RM = rm -f
24endif
25
26
27
28COMMON= main.c gd_bmp.c
29
30INCLUDE=-I ../libwps/src \
31 -I $(ROOT)/apps/gui \
32 -I $(ROOT)/firmware/export \
33 -I $(ROOT)/apps/recorder \
34 -I $(ROOT)/apps \
35 -I .
36
37CFLAGS = -g -Wall
38
39all:
40 $(CC) $(INCLUDE) $(CFLAGS) $(COMMON) -rdynamic -ldl -lgd -lpng -o screenshot
41
42clean:
43 $(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 @@
1/* $Id$ */
2#ifdef __cplusplus
3extern "C" {
4#endif
5
6/*
7 gd_bmp.c
8
9 Bitmap format support for libgd
10
11 * Written 2007, Scott MacVicar
12 ---------------------------------------------------------------------------
13
14 Todo:
15
16 RLE4, RLE8 and Bitfield encoding
17 Add full support for Windows v4 and Windows v5 header formats
18
19 ----------------------------------------------------------------------------
20 */
21
22#ifndef BMP_H
23#define BMP_H 1
24
25#define BMP_PALETTE_3 1
26#define BMP_PALETTE_4 2
27
28#define BMP_WINDOWS_V3 40
29#define BMP_OS2_V1 12
30#define BMP_OS2_V2 64
31#define BMP_WINDOWS_V4 108
32#define BMP_WINDOWS_V5 124
33
34#define BMP_BI_RGB 0
35#define BMP_BI_RLE8 1
36#define BMP_BI_RLE4 2
37#define BMP_BI_BITFIELDS 3
38#define BMP_BI_JPEG 4
39#define BMP_BI_PNG 5
40
41#define BMP_RLE_COMMAND 0
42#define BMP_RLE_ENDOFLINE 0
43#define BMP_RLE_ENDOFBITMAP 1
44#define BMP_RLE_DELTA 2
45
46#define BMP_RLE_TYPE_RAW 0
47#define BMP_RLE_TYPE_RLE 1
48
49/* BMP header. */
50typedef struct
51{
52 /* 16 bit - header identifying the type */
53 signed short int magic;
54
55 /* 32bit - size of the file */
56 int size;
57
58 /* 16bit - these two are in the spec but "reserved" */
59 signed short int reserved1;
60 signed short int reserved2;
61
62 /* 32 bit - offset of the bitmap header from data in bytes */
63 signed int off;
64
65} bmp_hdr_t;
66
67/* BMP info. */
68typedef struct
69{
70 /* 16bit - Type, ie Windows or OS/2 for the palette info */
71 signed short int type;
72 /* 32bit - The length of the bitmap information header in bytes. */
73 signed int len;
74
75 /* 32bit - The width of the bitmap in pixels. */
76 signed int width;
77
78 /* 32bit - The height of the bitmap in pixels. */
79 signed int height;
80
81 /* 8 bit - The bitmap data is specified in top-down order. */
82 signed char topdown;
83
84 /* 16 bit - The number of planes. This must be set to a value of one. */
85 signed short int numplanes;
86
87 /* 16 bit - The number of bits per pixel. */
88 signed short int depth;
89
90 /* 32bit - The type of compression used. */
91 signed int enctype;
92
93 /* 32bit - The size of the image in bytes. */
94 signed int size;
95
96 /* 32bit - The horizontal resolution in pixels/metre. */
97 signed int hres;
98
99 /* 32bit - The vertical resolution in pixels/metre. */
100 signed int vres;
101
102 /* 32bit - The number of color indices used by the bitmap. */
103 signed int numcolors;
104
105 /* 32bit - The number of color indices important for displaying the bitmap. */
106 signed int mincolors;
107
108} bmp_info_t;
109
110#endif
111
112#ifdef __cplusplus
113}
114#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 @@
1/*
2 Stolen from http://cvs.php.net/viewcvs.cgi/gd/playground/gdbmp/
3*/
4
5/*
6 gd_bmp.c
7
8 Bitmap format support for libgd
9
10 * Written 2007, Scott MacVicar
11 ---------------------------------------------------------------------------
12
13 Todo:
14
15 Bitfield encoding
16
17 ----------------------------------------------------------------------------
18 */
19/* $Id$ */
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <stdio.h>
25#include <math.h>
26#include <string.h>
27#include <stdlib.h>
28#include "gd.h"
29#include "bmp.h"
30
31extern void* gdCalloc (size_t nmemb, size_t size);
32
33static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
34static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
35static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
36static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
37static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
38
39static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
40static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
41static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
42static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
43static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
44
45#if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
46/* Byte helper functions, since added to GD 2.1 */
47static int gdGetIntLSB(signed int *result, gdIOCtx * ctx);
48static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx);
49#endif
50
51#define BMP_DEBUG(s)
52
53gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile);
54
55gdImagePtr gdImageCreateFromBmp(FILE * inFile)
56{
57 gdImagePtr im = 0;
58 gdIOCtx *in = gdNewFileCtx(inFile);
59 im = gdImageCreateFromBmpCtx(in);
60 in->gd_free(in);
61 return im;
62}
63
64gdImagePtr gdImageCreateFromBmpPtr(int size, void *data)
65{
66 gdImagePtr im;
67 gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
68 im = gdImageCreateFromBmpCtx(in);
69 in->gd_free(in);
70 return im;
71}
72
73gdImagePtr gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
74{
75 bmp_hdr_t *hdr;
76 bmp_info_t *info;
77 gdImagePtr im = NULL;
78 int error = 0;
79
80 if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
81 return NULL;
82 }
83
84 if (bmp_read_header(infile, hdr)) {
85 gdFree(hdr);
86 return NULL;
87 }
88
89 if (hdr->magic != 0x4d42) {
90 gdFree(hdr);
91 return NULL;
92 }
93
94 if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
95 gdFree(hdr);
96 return NULL;
97 }
98
99 if (bmp_read_info(infile, info)) {
100 gdFree(hdr);
101 gdFree(info);
102 return NULL;
103 }
104
105 BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
106 BMP_DEBUG(printf("Width: %d\n", info->width));
107 BMP_DEBUG(printf("Height: %d\n", info->height));
108 BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
109 BMP_DEBUG(printf("Depth: %d\n", info->depth));
110 BMP_DEBUG(printf("Offset: %d\n", hdr->off));
111
112 if (info->depth >= 16) {
113 im = gdImageCreateTrueColor(info->width, info->height);
114 } else {
115 im = gdImageCreate(info->width, info->height);
116 }
117
118 if (!im) {
119 gdFree(hdr);
120 gdFree(info);
121 return NULL;
122 }
123
124 switch (info->depth) {
125 case 1:
126 BMP_DEBUG(printf("1-bit image\n"));
127 error = bmp_read_1bit(im, infile, info, hdr);
128 break;
129 case 4:
130 BMP_DEBUG(printf("4-bit image\n"));
131 error = bmp_read_4bit(im, infile, info, hdr);
132 break;
133 case 8:
134 BMP_DEBUG(printf("8-bit image\n"));
135 error = bmp_read_8bit(im, infile, info, hdr);
136 break;
137 case 16:
138 case 24:
139 case 32:
140 BMP_DEBUG(printf("Direct BMP image\n"));
141 error = bmp_read_direct(im, infile, info, hdr);
142 break;
143 default:
144 BMP_DEBUG(printf("Unknown bit count\n"));
145 error = 1;
146 }
147
148 gdFree(hdr);
149 gdFree(info);
150
151 if (error) {
152 gdImageDestroy(im);
153 return NULL;
154 }
155
156 return im;
157}
158
159static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
160{
161 if(
162 !gdGetWordLSB(&hdr->magic, infile) ||
163 !gdGetIntLSB(&hdr->size, infile) ||
164 !gdGetWordLSB(&hdr->reserved1, infile) ||
165 !gdGetWordLSB(&hdr->reserved2 , infile) ||
166 !gdGetIntLSB(&hdr->off , infile)
167 ) {
168 return 1;
169 }
170 return 0;
171}
172
173static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
174{
175 /* read BMP length so we can work out the version */
176 if (!gdGetIntLSB(&info->len, infile)) {
177 return 1;
178 }
179
180 switch (info->len) {
181 /* For now treat Windows v4 + v5 as v3 */
182 case BMP_WINDOWS_V3:
183 case BMP_WINDOWS_V4:
184 case BMP_WINDOWS_V5:
185 BMP_DEBUG(printf("Reading Windows Header\n"));
186 if (bmp_read_windows_v3_info(infile, info)) {
187 return 1;
188 }
189 break;
190 case BMP_OS2_V1:
191 if (bmp_read_os2_v1_info(infile, info)) {
192 return 1;
193 }
194 break;
195 case BMP_OS2_V2:
196 if (bmp_read_os2_v2_info(infile, info)) {
197 return 1;
198 }
199 break;
200 default:
201 BMP_DEBUG(printf("Unhandled bitmap\n"));
202 return 1;
203 }
204 return 0;
205}
206
207static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
208{
209 if (
210 !gdGetIntLSB(&info->width, infile) ||
211 !gdGetIntLSB(&info->height, infile) ||
212 !gdGetWordLSB(&info->numplanes, infile) ||
213 !gdGetWordLSB(&info->depth, infile) ||
214 !gdGetIntLSB(&info->enctype, infile) ||
215 !gdGetIntLSB(&info->size, infile) ||
216 !gdGetIntLSB(&info->hres, infile) ||
217 !gdGetIntLSB(&info->vres, infile) ||
218 !gdGetIntLSB(&info->numcolors, infile) ||
219 !gdGetIntLSB(&info->mincolors, infile)
220 ) {
221 return 1;
222 }
223
224 if (info->height < 0) {
225 info->topdown = 1;
226 info->height = -info->height;
227 } else {
228 info->topdown = 0;
229 }
230
231 info->type = BMP_PALETTE_4;
232
233 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
234 info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
235 return 1;
236 }
237
238 return 0;
239}
240
241static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
242{
243 if (
244 !gdGetWordLSB((signed short int *)&info->width, infile) ||
245 !gdGetWordLSB((signed short int *)&info->height, infile) ||
246 !gdGetWordLSB(&info->numplanes, infile) ||
247 !gdGetWordLSB(&info->depth, infile)
248 ) {
249 return 1;
250 }
251
252 /* OS2 v1 doesn't support topdown */
253 info->topdown = 0;
254
255 info->numcolors = 1 << info->depth;
256 info->type = BMP_PALETTE_3;
257
258 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
259 info->depth <= 0 || info->numcolors < 0) {
260 return 1;
261 }
262
263 return 0;
264}
265
266static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
267{
268 char useless_bytes[24];
269 if (
270 !gdGetIntLSB(&info->width, infile) ||
271 !gdGetIntLSB(&info->height, infile) ||
272 !gdGetWordLSB(&info->numplanes, infile) ||
273 !gdGetWordLSB(&info->depth, infile) ||
274 !gdGetIntLSB(&info->enctype, infile) ||
275 !gdGetIntLSB(&info->size, infile) ||
276 !gdGetIntLSB(&info->hres, infile) ||
277 !gdGetIntLSB(&info->vres, infile) ||
278 !gdGetIntLSB(&info->numcolors, infile) ||
279 !gdGetIntLSB(&info->mincolors, infile)
280 ) {
281 return 1;
282 }
283
284 /* Lets seek the next 24 pointless bytes, we don't care too much about it */
285 if (!gdGetBuf(useless_bytes, 24, infile)) {
286 return 1;
287 }
288
289 if (info->height < 0) {
290 info->topdown = 1;
291 info->height = -info->height;
292 } else {
293 info->topdown = 0;
294 }
295
296 info->type = BMP_PALETTE_4;
297
298 if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
299 info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
300 return 1;
301 }
302
303
304 return 0;
305}
306
307static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
308{
309 int ypos = 0, xpos = 0, row = 0;
310 int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
311 signed short int data = 0;
312
313 switch(info->enctype) {
314 case BMP_BI_RGB:
315 /* no-op */
316 break;
317
318 case BMP_BI_BITFIELDS:
319 if (info->depth == 24) {
320 BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
321 return 1;
322 }
323 BMP_DEBUG(printf("Currently no bitfield support\n"));
324 return 1;
325 break;
326
327 case BMP_BI_RLE8:
328 if (info->depth != 8) {
329 BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
330 return 1;
331 }
332 case BMP_BI_RLE4:
333 if (info->depth != 4) {
334 BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
335 return 1;
336 }
337 case BMP_BI_JPEG:
338 case BMP_BI_PNG:
339 default:
340 BMP_DEBUG(printf("Unsupported BMP compression format\n"));
341 return 1;
342 }
343
344 /* There is a chance the data isn't until later, would be wierd but it is possible */
345 if (gdTell(infile) != header->off) {
346 /* Should make sure we don't seek past the file size */
347 gdSeek(infile, header->off);
348 }
349
350 /* The line must be divisible by 4, else its padded with NULLs */
351 padding = ((int)(info->depth / 8) * info->width) % 4;
352 if (padding) {
353 padding = 4 - padding;
354 }
355
356
357 for (ypos = 0; ypos < info->height; ++ypos) {
358 if (info->topdown) {
359 row = ypos;
360 } else {
361 row = info->height - ypos - 1;
362 }
363
364 for (xpos = 0; xpos < info->width; xpos++) {
365 if (info->depth == 16) {
366 if (!gdGetWordLSB(&data, infile)) {
367 return 1;
368 }
369 BMP_DEBUG(printf("Data: %X\n", data));
370 red = ((data & 0x7C00) >> 10) << 3;
371 green = ((data & 0x3E0) >> 5) << 3;
372 blue = (data & 0x1F) << 3;
373 BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
374 } else if (info->depth == 24) {
375 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
376 return 1;
377 }
378 } else {
379 if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
380 return 1;
381 }
382 }
383 /*alpha = gdAlphaMax - (alpha >> 1);*/
384 gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
385 }
386 for (xpos = padding; xpos > 0; --xpos) {
387 if (!gdGetByte(&red, infile)) {
388 return 1;
389 }
390 }
391 }
392
393 return 0;
394}
395
396static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
397{
398 int i;
399 int r, g, b, z;
400
401 for (i = 0; i < count; i++) {
402 if (
403 !gdGetByte(&r, infile) ||
404 !gdGetByte(&g, infile) ||
405 !gdGetByte(&b, infile) ||
406 (read_four && !gdGetByte(&z, infile))
407 ) {
408 return 1;
409 }
410 im->red[i] = r;
411 im->green[i] = g;
412 im->blue[i] = b;
413 im->open[i] = 1;
414 }
415 return 0;
416}
417
418static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
419{
420 int ypos = 0, xpos = 0, row = 0, index = 0;
421 int padding = 0, current_byte = 0, bit = 0;
422
423 if (info->enctype != BMP_BI_RGB) {
424 return 1;
425 }
426
427 if (!info->numcolors) {
428 info->numcolors = 2;
429 } else if (info->numcolors < 0 || info->numcolors > 2) {
430 return 1;
431 }
432
433 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
434 return 1;
435 }
436
437 im->colorsTotal = info->numcolors;
438
439 /* There is a chance the data isn't until later, would be wierd but it is possible */
440 if (gdTell(infile) != header->off) {
441 /* Should make sure we don't seek past the file size */
442 gdSeek(infile, header->off);
443 }
444
445 /* The line must be divisible by 4, else its padded with NULLs */
446 padding = ((int)ceill(0.1 * info->width)) % 4;
447 if (padding) {
448 padding = 4 - padding;
449 }
450
451 for (ypos = 0; ypos < info->height; ++ypos) {
452 if (info->topdown) {
453 row = ypos;
454 } else {
455 row = info->height - ypos - 1;
456 }
457
458 for (xpos = 0; xpos < info->width; xpos += 8) {
459 /* Bitmaps are always aligned in bytes so we'll never overflow */
460 if (!gdGetByte(&current_byte, infile)) {
461 return 1;
462 }
463
464 for (bit = 0; bit < 8; bit++) {
465 index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
466 if (im->open[index]) {
467 im->open[index] = 0;
468 }
469 gdImageSetPixel(im, xpos + bit, row, index);
470 /* No need to read anything extra */
471 if ((xpos + bit) >= info->width) {
472 break;
473 }
474 }
475 }
476
477 for (xpos = padding; xpos > 0; --xpos) {
478 if (!gdGetByte(&index, infile)) {
479 return 1;
480 }
481 }
482 }
483 return 0;
484}
485
486static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
487{
488 int ypos = 0, xpos = 0, row = 0, index = 0;
489 int padding = 0, current_byte = 0;
490
491 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
492 return 1;
493 }
494
495 if (!info->numcolors) {
496 info->numcolors = 16;
497 } else if (info->numcolors < 0 || info->numcolors > 16) {
498 return 1;
499 }
500
501 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
502 return 1;
503 }
504
505 im->colorsTotal = info->numcolors;
506
507 /* There is a chance the data isn't until later, would be wierd but it is possible */
508 if (gdTell(infile) != header->off) {
509 /* Should make sure we don't seek past the file size */
510 gdSeek(infile, header->off);
511 }
512
513 /* The line must be divisible by 4, else its padded with NULLs */
514 padding = ((int)ceil(0.5 * info->width)) % 4;
515 if (padding) {
516 padding = 4 - padding;
517 }
518
519 switch (info->enctype) {
520 case BMP_BI_RGB:
521 for (ypos = 0; ypos < info->height; ++ypos) {
522 if (info->topdown) {
523 row = ypos;
524 } else {
525 row = info->height - ypos - 1;
526 }
527
528 for (xpos = 0; xpos < info->width; xpos += 2) {
529 if (!gdGetByte(&current_byte, infile)) {
530 return 1;
531 }
532
533 index = (current_byte >> 4) & 0x0f;
534 if (im->open[index]) {
535 im->open[index] = 0;
536 }
537 gdImageSetPixel(im, xpos, row, index);
538
539 /* This condition may get called often, potential optimsations */
540 if (xpos >= info->width) {
541 break;
542 }
543
544 index = current_byte & 0x0f;
545 if (im->open[index]) {
546 im->open[index] = 0;
547 }
548 gdImageSetPixel(im, xpos + 1, row, index);
549 }
550
551 for (xpos = padding; xpos > 0; --xpos) {
552 if (!gdGetByte(&index, infile)) {
553 return 1;
554 }
555 }
556 }
557 break;
558
559 case BMP_BI_RLE4:
560 if (bmp_read_rle(im, infile, info)) {
561 return 1;
562 }
563 break;
564
565 default:
566 return 1;
567 }
568 return 0;
569}
570
571static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
572{
573 int ypos = 0, xpos = 0, row = 0, index = 0;
574 int padding = 0;
575
576 if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
577 return 1;
578 }
579
580 if (!info->numcolors) {
581 info->numcolors = 256;
582 } else if (info->numcolors < 0 || info->numcolors > 256) {
583 return 1;
584 }
585
586 if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
587 return 1;
588 }
589
590 im->colorsTotal = info->numcolors;
591
592 /* There is a chance the data isn't until later, would be wierd but it is possible */
593 if (gdTell(infile) != header->off) {
594 /* Should make sure we don't seek past the file size */
595 gdSeek(infile, header->off);
596 }
597
598 /* The line must be divisible by 4, else its padded with NULLs */
599 padding = (1 * info->width) % 4;
600 if (padding) {
601 padding = 4 - padding;
602 }
603
604 switch (info->enctype) {
605 case BMP_BI_RGB:
606 for (ypos = 0; ypos < info->height; ++ypos) {
607 if (info->topdown) {
608 row = ypos;
609 } else {
610 row = info->height - ypos - 1;
611 }
612
613 for (xpos = 0; xpos < info->width; ++xpos) {
614 if (!gdGetByte(&index, infile)) {
615 return 1;
616 }
617
618 if (im->open[index]) {
619 im->open[index] = 0;
620 }
621 gdImageSetPixel(im, xpos, row, index);
622 }
623 /* Could create a new variable, but it isn't really worth it */
624 for (xpos = padding; xpos > 0; --xpos) {
625 if (!gdGetByte(&index, infile)) {
626 return 1;
627 }
628 }
629 }
630 break;
631
632 case BMP_BI_RLE8:
633 if (bmp_read_rle(im, infile, info)) {
634 return 1;
635 }
636 break;
637
638 default:
639 return 1;
640 }
641 return 0;
642}
643
644static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
645{
646 int ypos = 0, xpos = 0, row = 0, index = 0;
647 int rle_length = 0, rle_data = 0;
648 int padding = 0;
649 int i = 0, j = 0;
650 int pixels_per_byte = 8 / info->depth;
651
652 for (ypos = 0; ypos < info->height && xpos <= info->width;) {
653 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
654 return 1;
655 }
656 row = info->height - ypos - 1;
657
658 if (rle_length != BMP_RLE_COMMAND) {
659 if (im->open[rle_data]) {
660 im->open[rle_data] = 0;
661 }
662
663 for (i = 0; (i < rle_length) && (xpos < info->width);) {
664 for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
665 index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
666 if (im->open[index]) {
667 im->open[index] = 0;
668 }
669 gdImageSetPixel(im, xpos, row, index);
670 }
671 }
672 } else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
673 /* Uncompressed RLE needs to be even */
674 padding = 0;
675 for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
676 int max_pixels = pixels_per_byte;
677
678 if (!gdGetByte(&index, infile)) {
679 return 1;
680 }
681 padding++;
682
683 if (rle_data - i < max_pixels) {
684 max_pixels = rle_data - i;
685 }
686
687 for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
688 int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
689 if (im->open[temp]) {
690 im->open[temp] = 0;
691 }
692 gdImageSetPixel(im, xpos, row, temp);
693 }
694 }
695
696 /* Make sure the bytes read are even */
697 if (padding % 2 && !gdGetByte(&index, infile)) {
698 return 1;
699 }
700 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
701 /* Next Line */
702 xpos = 0;
703 ypos++;
704 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
705 /* Delta Record, used for bmp files that contain other data*/
706 if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
707 return 1;
708 }
709 xpos += rle_length;
710 ypos += rle_data;
711 } else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
712 /* End of bitmap */
713 break;
714 }
715 }
716 return 0;
717}
718
719#if GD_MAJOR_VERSION == 2 && GD_MINOR_VERSION < 1
720static int gdGetWordLSB(signed short int *result, gdIOCtx * ctx)
721{
722 unsigned int high = 0, low = 0;
723 low = (ctx->getC) (ctx);
724 if (low == EOF) {
725 return 0;
726 }
727
728 high = (ctx->getC) (ctx);
729 if (high == EOF) {
730 return 0;
731 }
732
733 if (result) {
734 *result = (high << 8) | low;
735 }
736
737 return 1;
738}
739
740static int gdGetIntLSB(signed int *result, gdIOCtx * ctx)
741{
742 int c = 0;
743 unsigned int r = 0;
744
745 c = (ctx->getC) (ctx);
746 if (c == EOF) {
747 return 0;
748 }
749 r |= (c << 24);
750 r >>= 8;
751
752 c = (ctx->getC) (ctx);
753 if (c == EOF) {
754 return 0;
755 }
756 r |= (c << 24);
757 r >>= 8;
758
759 c = (ctx->getC) (ctx);
760 if (c == EOF) {
761 return 0;
762 }
763 r |= (c << 24);
764 r >>= 8;
765
766 c = (ctx->getC) (ctx);
767 if (c == EOF) {
768 return 0;
769 }
770 r |= (c << 24);
771
772 if (result) {
773 *result = (signed int)r;
774 }
775
776 return 1;
777}
778#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <stdarg.h>
24#include <string.h>
25#include <dlfcn.h>
26#include <unistd.h>
27#include "gd.h"
28#include "gdfonts.h"
29#include "api.h"
30
31#define DEBUGF1 _debug
32#define DEBUGF2 if(verbose) _debug
33
34#define getFont() gdFontGetSmall()
35
36static struct trackstate mp3data =
37{
38(char*)"Test title",
39(char*)"Test artist",
40(char*)"Test album",
41(char*)"Test genre",
42(char*)"Test disc",
43(char*)"Test track",
44(char*)"Test year",
45(char*)"Test composer",
46(char*)"Test comment",
47(char*)"Test album artist",
48(char*)"Test grouping",
491, /* int discnum */
501, /* int tracknum */
511, /* int version */
521, /* int layer */
532008, /* int year */
54
55100, /* int length */
5670 /* int elapsed */
57};
58
59static struct wpsstate wpsdata = {-20, -1, -1, 70, API_STATUS_FASTFORWARD};
60 /* volume, fontheight, fontwidth, battery_level, audio_status */
61
62static struct proxy_api api;
63static bool verbose = false;
64static int (*wps_init)(const char* buff, struct proxy_api *api, bool isfile);
65static int (*wps_display)();
66static int (*wps_refresh)();
67static gdImagePtr framebuffer;
68static gdImagePtr backdrop;
69
70extern gdImagePtr gdImageCreateFromBmp(FILE * inFile);
71extern char *get_current_dir_name (void) __THROW;
72
73int _debug(const char* fmt,...)
74{
75#if 0 /* Doesn't want to compile ?? */
76 struct va_list ap;
77
78 va_start(ap, fmt);
79
80 fprintf(stdout, "[DBG] ");
81 vfprintf(stdout, fmt, ap);
82 fprintf(stdout, "\n");
83
84 va_end(ap);
85
86 return 0;
87#else
88 return -1;
89#endif
90}
91
92void _putsxy(int x, int y, const unsigned char *str)
93{
94 struct viewport_api avp;
95 int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
96
97 api.get_current_vp(&avp);
98
99 gdImageString(framebuffer, getFont(), x + avp.x, y + avp.y - avp.fontheight, (unsigned char*)str, black);
100}
101
102void _transparent_bitmap_part(const void *src, int src_x, int src_y,
103 int stride, int x, int y, int width, int height)
104{
105 FILE *_image;
106 gdImagePtr image;
107 int pink;
108
109 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);
110
111 _image = fopen(src, "rb");
112 if(_image == NULL)
113 return;
114
115 image = gdImageCreateFromBmp(_image);
116 fclose(_image);
117
118 pink = gdTrueColor(255, 0, 255);
119 gdImageColorTransparent(image, pink);
120
121 gdImageCopy(framebuffer, image, x, y, src_x, src_y, width, height);
122
123 gdImageDestroy(image);
124}
125
126void _bitmap_part(const void *src, int src_x, int src_y,
127 int stride, int x, int y, int width, int height)
128{
129 FILE *_image;
130 gdImagePtr image;
131
132 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);
133
134 _image = fopen(src, "rb");
135 if(_image == NULL)
136 return;
137
138 image = gdImageCreateFromBmp(_image);
139 fclose(_image);
140
141 gdImageCopy(framebuffer, image, x, y, src_x, src_y, width, height);
142
143 gdImageDestroy(image);
144}
145
146void _drawpixel(int x, int y)
147{
148 int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
149 gdImageSetPixel(framebuffer, x, y, black);
150}
151
152void _fillrect(int x, int y, int width, int height)
153{
154 /* Don't draw this as backdrop is used */
155#if 0
156 int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
157 gdImageFilledRectangle(framebuffer, x, y, x+width, y+height, black);
158#endif
159}
160
161void _hline(int x1, int x2, int y)
162{
163 int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
164 gdImageLine(framebuffer, x1, y, x2, y, black);
165}
166
167void _vline(int x, int y1, int y2)
168{
169 int black = gdImageColorAllocate(framebuffer, 0, 0, 0);
170 gdImageLine(framebuffer, x, y1, x, y2, black);
171}
172
173void _clear_viewport(int x, int y, int w, int h, int color)
174{
175 if(backdrop == NULL)
176 return;
177
178 gdImageCopy(framebuffer, backdrop, x, y, x, y, w, h);
179}
180
181static bool _load_wps_backdrop(char* filename)
182{
183 FILE *image;
184 if(backdrop != NULL)
185 gdImageDestroy(backdrop);
186
187 DEBUGF2("load backdrop: %s", filename);
188
189 image = fopen(filename, "rb");
190 if(image == NULL)
191 return false;
192
193 backdrop = gdImageCreateFromBmp(image);
194 fclose(image);
195
196 return true;
197}
198
199int _read_bmp_file(const char* filename, int *width, int *height)
200{
201 FILE *_image;
202 gdImagePtr image;
203
204 DEBUGF2("load backdrop: %s", filename);
205
206 _image = fopen(filename, "rb");
207 if(_image == NULL)
208 return 0;
209
210 image = gdImageCreateFromBmp(_image);
211 fclose(_image);
212
213 *width = image->sx;
214 *height = image->sy;
215
216 gdImageDestroy(image);
217
218 return 1;
219}
220
221static void _drawBackdrop()
222{
223 if(backdrop == NULL)
224 return;
225
226 gdImageCopy(framebuffer, backdrop, 0, 0, 0, 0, backdrop->sx, backdrop->sy);
227}
228
229static int screenshot(char *model, char *wps, char *png)
230{
231 char lib[255];
232 void *handle;
233 FILE *out, *in;
234
235 in = fopen(wps, "rb");
236 if(in == NULL)
237 {
238 fprintf(stderr, "[ERR] Cannot open WPS: %s\n", wps);
239 return -1;
240 }
241 fclose(in);
242
243 out = fopen(png, "wb");
244 if(out == NULL)
245 {
246 fprintf(stderr, "[ERR] Cannot open PNG: %s\n", png);
247 return -2;
248 }
249
250 snprintf(lib, 255, "%s/libwps_%s.so", (char*)get_current_dir_name(), (char*)model);
251 handle = dlopen(lib, RTLD_LAZY);
252 if (!handle)
253 {
254 fprintf(stderr, "[ERR] Cannot open library: %s\n", dlerror());
255 fclose(out);
256 return -3;
257 }
258
259 wps_init = dlsym(handle, "wps_init");
260 wps_display = dlsym(handle, "wps_display");
261 wps_refresh = dlsym(handle, "wps_refresh");
262
263 if (!wps_init || !wps_display || !wps_refresh)
264 {
265 fprintf(stderr, "[ERR] Failed to resolve funcs!");
266 dlclose(handle);
267 fclose(out);
268 return -4;
269 }
270
271 memset(&api, 0, sizeof(struct proxy_api));
272
273 if(verbose)
274 api.verbose = 3;
275 else
276 api.verbose = 0;
277
278 api.putsxy = &_putsxy;
279 api.transparent_bitmap_part = &_transparent_bitmap_part;
280 api.bitmap_part = &_bitmap_part;
281 api.drawpixel = &_drawpixel;
282 api.fillrect = &_fillrect;
283 api.hline = &_hline;
284 api.vline = &_vline;
285 api.clear_viewport = &_clear_viewport;
286 api.load_wps_backdrop = &_load_wps_backdrop;
287 api.read_bmp_file = &_read_bmp_file;
288 api.debugf = &_debug;
289
290 wps_init(wps, &api, true);
291
292 framebuffer = gdImageCreateTrueColor(api.getwidth(), api.getheight());
293
294 _drawBackdrop();
295
296 if(strcmp(api.get_model_name(), model) != 0)
297 {
298 fprintf(stderr, "[ERR] Model name doesn't match the one supplied by the library\n");
299 fprintf(stderr, " %s <-> %s\n", model, api.get_model_name());
300 dlclose(handle);
301 fclose(out);
302 gdImageDestroy(framebuffer);
303 gdImageDestroy(backdrop);
304 wps_init = NULL;
305 wps_display = NULL;
306 wps_refresh = NULL;
307 return -5;
308 }
309 fprintf(stdout, "[INFO] Model: %s\n", api.get_model_name());
310
311 wpsdata.fontheight = getFont()->h;
312 wpsdata.fontwidth = getFont()->w;
313 api.set_wpsstate(wpsdata);
314 api.set_trackstate(mp3data);
315 api.set_next_trackstate(mp3data);
316
317 _drawBackdrop();
318 wps_refresh();
319 gdImagePng(framebuffer, out);
320
321 fprintf(stdout, "[INFO] Image written\n");
322
323 dlclose(handle);
324 fclose(out);
325 gdImageDestroy(framebuffer);
326 gdImageDestroy(backdrop);
327
328 wps_init = NULL;
329 wps_display = NULL;
330 wps_refresh = NULL;
331
332 return 0;
333}
334
335static void usage(void)
336{
337 fprintf(stderr, "Usage: screenshot [-V] <MODEL> <WPS_FILE> <OUT_PNG>\n");
338 fprintf(stderr, "Example: screenshot h10_5gb iCatcher.wps out.png\n");
339}
340
341int main(int argc, char ** argv)
342{
343 if(argc < 4)
344 {
345 usage();
346 return -1;
347 }
348
349 if(strcmp(argv[1], "-V") == 0)
350 {
351 verbose = true;
352 return screenshot(argv[2], argv[3], argv[4]);
353 }
354 else
355 {
356 verbose = false;
357 return screenshot(argv[1], argv[2], argv[3]);
358 }
359
360 return 0;
361}