~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to drv_Image.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:24:15 UTC
  • mto: This revision was merged to the branch mainline in revision 750.
  • Revision ID: siretart@tauware.de-20110427172415-6n4aptmvmz0eztvm
Tags: upstream-0.11.0~svn1143
ImportĀ upstreamĀ versionĀ 0.11.0~svn1143

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: drv_Image.c 840 2007-09-09 12:17:42Z michael $
 
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_Image.c $
 
3
 *
 
4
 * new style Image (PPM/PNG) Driver for LCD4Linux 
 
5
 *
 
6
 * Copyright (C) 2003 Michael Reinelt <michael@reinelt.co.at>
 
7
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 
8
 *
 
9
 * This file is part of LCD4Linux.
 
10
 *
 
11
 * LCD4Linux is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2, or (at your option)
 
14
 * any later version.
 
15
 *
 
16
 * LCD4Linux is distributed in the hope that it will be useful,
 
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
 * GNU General Public License for more details.
 
20
 *
 
21
 * You should have received a copy of the GNU General Public License
 
22
 * along with this program; if not, write to the Free Software
 
23
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
24
 *
 
25
 */
 
26
 
 
27
/* 
 
28
 *
 
29
 * exported fuctions:
 
30
 *
 
31
 * struct DRIVER drv_Image
 
32
 *
 
33
 */
 
34
 
 
35
 
 
36
#include "config.h"
 
37
 
 
38
#include <stdlib.h>
 
39
#include <stdio.h>
 
40
#include <string.h>
 
41
#include <errno.h>
 
42
#include <unistd.h>
 
43
#include <termios.h>
 
44
#include <fcntl.h>
 
45
#include <sys/time.h>
 
46
 
 
47
 
 
48
#ifdef WITH_PNG
 
49
 
 
50
#ifdef HAVE_GD_GD_H
 
51
#include <gd/gd.h>
 
52
#else
 
53
#ifdef HAVE_GD_H
 
54
#include <gd.h>
 
55
#else
 
56
#error "gd.h not found!"
 
57
#error "cannot compile PNG driver"
 
58
#endif
 
59
#endif
 
60
 
 
61
#if GD2_VERS != 2
 
62
#error "lcd4linux requires libgd version 2"
 
63
#error "cannot compile PNG driver"
 
64
#endif
 
65
 
 
66
#endif
 
67
 
 
68
 
 
69
#include "debug.h"
 
70
#include "cfg.h"
 
71
#include "timer.h"
 
72
#include "qprintf.h"
 
73
#include "plugin.h"
 
74
#include "drv.h"
 
75
#include "drv_generic_graphic.h"
 
76
 
 
77
#ifdef WITH_DMALLOC
 
78
#include <dmalloc.h>
 
79
#endif
 
80
 
 
81
static char Name[] = "Image";
 
82
 
 
83
static enum { NIL, PPM, PNG } Format;
 
84
 
 
85
static int pixel = -1;          /* pointsize in pixel */
 
86
static int pgap = 0;            /* gap between points */
 
87
static int rgap = 0;            /* row gap between lines */
 
88
static int cgap = 0;            /* column gap between characters */
 
89
static int border = 0;          /* window border */
 
90
 
 
91
static int dimx, dimy;          /* total window dimension in pixel */
 
92
 
 
93
static RGBA BC;
 
94
static RGBA *drv_IMG_FB = NULL;
 
95
 
 
96
static int dirty = 1;
 
97
 
 
98
/****************************************/
 
99
/***  hardware dependant functions    ***/
 
100
/****************************************/
 
101
 
 
102
#ifdef WITH_PPM
 
103
static int drv_IMG_flush_PPM(void)
 
104
{
 
105
    static int seq = 0;
 
106
    static RGBA *bitbuf = NULL;
 
107
    static unsigned char *rowbuf = NULL;
 
108
    int xsize, ysize, row, col, i;
 
109
    char path[256], tmp[256], buffer[256];
 
110
    int fd;
 
111
 
 
112
    xsize = 2 * border + (DCOLS / XRES - 1) * cgap + DCOLS * pixel + (DCOLS - 1) * pgap;
 
113
    ysize = 2 * border + (DROWS / YRES - 1) * rgap + DROWS * pixel + (DROWS - 1) * pgap;
 
114
 
 
115
    if (bitbuf == NULL) {
 
116
        if ((bitbuf = malloc(xsize * ysize * sizeof(*bitbuf))) == NULL) {
 
117
            error("%s: malloc() failed: %s", Name, strerror(errno));
 
118
            return -1;
 
119
        }
 
120
    }
 
121
 
 
122
    if (rowbuf == NULL) {
 
123
        if ((rowbuf = malloc(3 * xsize * sizeof(*rowbuf))) == NULL) {
 
124
            error("Raster: malloc() failed: %s", strerror(errno));
 
125
            return -1;
 
126
        }
 
127
    }
 
128
 
 
129
    for (i = 0; i < xsize * ysize; i++) {
 
130
        bitbuf[i] = BC;
 
131
    }
 
132
 
 
133
    for (row = 0; row < DROWS; row++) {
 
134
        int y = border + (row / YRES) * rgap + row * (pixel + pgap);
 
135
        for (col = 0; col < DCOLS; col++) {
 
136
            int x = border + (col / XRES) * cgap + col * (pixel + pgap);
 
137
            int a, b;
 
138
            for (a = 0; a < pixel; a++)
 
139
                for (b = 0; b < pixel; b++)
 
140
                    bitbuf[y * xsize + x + a * xsize + b] = drv_IMG_FB[row * DCOLS + col];
 
141
        }
 
142
    }
 
143
 
 
144
    snprintf(path, sizeof(path), output, seq++);
 
145
    qprintf(tmp, sizeof(tmp), "%s.tmp", path);
 
146
 
 
147
    /* remove the file */
 
148
    unlink(tmp);
 
149
 
 
150
    /* avoid symlink security hole:  */
 
151
    /* open it with O_EXCL will fail if the file exists.  */
 
152
    /* This should not happen because we just unlinked it. */
 
153
    if ((fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) {
 
154
        error("%s: open(%s) failed: %s", Name, tmp, strerror(errno));
 
155
        return -1;
 
156
    }
 
157
 
 
158
    qprintf(buffer, sizeof(buffer), "P6\n%d %d\n255\n", xsize, ysize);
 
159
    if (write(fd, buffer, strlen(buffer)) < 0) {
 
160
        error("%s: write(%s) failed: %s", Name, tmp, strerror(errno));
 
161
        return -1;
 
162
    }
 
163
 
 
164
    for (row = 0; row < ysize; row++) {
 
165
        int c = 0;
 
166
        for (col = 0; col < xsize; col++) {
 
167
            RGBA p = bitbuf[row * xsize + col];
 
168
            rowbuf[c++] = p.R;
 
169
            rowbuf[c++] = p.G;
 
170
            rowbuf[c++] = p.B;
 
171
        }
 
172
        if (write(fd, rowbuf, c) < 0) {
 
173
            error("%s: write(%s) failed: %s", Name, tmp, strerror(errno));
 
174
            break;
 
175
        }
 
176
    }
 
177
 
 
178
    if (close(fd) < 0) {
 
179
        error("%s: close(%s) failed: %s", Name, tmp, strerror(errno));
 
180
        return -1;
 
181
    }
 
182
    if (rename(tmp, path) < 0) {
 
183
        error("%s: rename(%s) failed: %s", Name, tmp, strerror(errno));
 
184
        return -1;
 
185
    }
 
186
 
 
187
    return 0;
 
188
}
 
189
#endif
 
190
 
 
191
#ifdef WITH_PNG
 
192
static int drv_IMG_flush_PNG(void)
 
193
{
 
194
    static int seq = 0;
 
195
    int xsize, ysize, row, col;
 
196
    char path[256], tmp[256];
 
197
    FILE *fp;
 
198
    int fd;
 
199
    gdImagePtr im;
 
200
 
 
201
    xsize = 2 * border + (DCOLS / XRES - 1) * cgap + DCOLS * pixel + (DCOLS - 1) * pgap;
 
202
    ysize = 2 * border + (DROWS / YRES - 1) * rgap + DROWS * pixel + (DROWS - 1) * pgap;
 
203
 
 
204
    im = gdImageCreateTrueColor(xsize, ysize);
 
205
    gdImageFilledRectangle(im, 0, 0, xsize, ysize, gdTrueColor(BC.R, BC.G, BC.B));
 
206
 
 
207
    for (row = 0; row < DROWS; row++) {
 
208
        int y = border + (row / YRES) * rgap + row * (pixel + pgap);
 
209
        for (col = 0; col < DCOLS; col++) {
 
210
            int x = border + (col / XRES) * cgap + col * (pixel + pgap);
 
211
            RGBA p = drv_IMG_FB[row * DCOLS + col];
 
212
            int c = gdTrueColor(p.R, p.G, p.B);
 
213
            gdImageFilledRectangle(im, x, y, x + pixel - 1, y + pixel - 1, c);
 
214
        }
 
215
    }
 
216
 
 
217
    snprintf(path, sizeof(path), output, seq++);
 
218
    qprintf(tmp, sizeof(tmp), "%s.tmp", path);
 
219
 
 
220
    /* remove the file */
 
221
    unlink(tmp);
 
222
 
 
223
    /* avoid symlink security hole:  */
 
224
    /* open it with O_EXCL will fail if the file exists.  */
 
225
    /* This should not happen because we just unlinked it. */
 
226
    if ((fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) {
 
227
        error("%s: open(%s) failed: %s", Name, tmp, strerror(errno));
 
228
        return -1;
 
229
    }
 
230
 
 
231
    if ((fp = fdopen(fd, "w")) == NULL) {
 
232
        error("%s: fdopen(%s) failed: %s\n", Name, tmp, strerror(errno));
 
233
        close(fd);
 
234
        return -1;
 
235
    }
 
236
 
 
237
    gdImagePng(im, fp);
 
238
    gdImageDestroy(im);
 
239
 
 
240
 
 
241
    if (fclose(fp) != 0) {
 
242
        error("%s: fclose(%s) failed: %s\n", Name, tmp, strerror(errno));
 
243
        return -1;
 
244
    }
 
245
 
 
246
    if (rename(tmp, path) < 0) {
 
247
        error("%s: rename(%s) failed: %s\n", Name, tmp, strerror(errno));
 
248
        return -1;
 
249
    }
 
250
 
 
251
    return 0;
 
252
}
 
253
#endif
 
254
 
 
255
 
 
256
static void drv_IMG_flush(void)
 
257
{
 
258
    switch (Format) {
 
259
    case PPM:
 
260
#ifdef WITH_PPM
 
261
        drv_IMG_flush_PPM();
 
262
#endif
 
263
        break;
 
264
    case PNG:
 
265
#ifdef WITH_PNG
 
266
        drv_IMG_flush_PNG();
 
267
#endif
 
268
        break;
 
269
    default:
 
270
        break;
 
271
    }
 
272
}
 
273
 
 
274
 
 
275
static void drv_IMG_timer( __attribute__ ((unused))
 
276
                          void *notused)
 
277
{
 
278
    if (dirty) {
 
279
        drv_IMG_flush();
 
280
        dirty = 0;
 
281
    }
 
282
}
 
283
 
 
284
 
 
285
static void drv_IMG_blit(const int row, const int col, const int height, const int width)
 
286
{
 
287
    int r, c;
 
288
 
 
289
    for (r = row; r < row + height; r++) {
 
290
        for (c = col; c < col + width; c++) {
 
291
            RGBA p1 = drv_IMG_FB[r * DCOLS + c];
 
292
            RGBA p2 = drv_generic_graphic_rgb(r, c);
 
293
            if (p1.R != p2.R || p1.G != p2.G || p1.B != p2.B) {
 
294
                drv_IMG_FB[r * DCOLS + c] = p2;
 
295
                dirty = 1;
 
296
            }
 
297
        }
 
298
    }
 
299
}
 
300
 
 
301
 
 
302
static int drv_IMG_start(const char *section)
 
303
{
 
304
    int i;
 
305
    char *s;
 
306
 
 
307
    if (output == NULL || *output == '\0') {
 
308
        error("%s: no output file specified (use -o switch)", Name);
 
309
        return -1;
 
310
    }
 
311
 
 
312
    /* read file format from config */
 
313
    s = cfg_get(section, "Format", NULL);
 
314
    if (s == NULL || *s == '\0') {
 
315
        error("%s: no '%s.Format' entry from %s", Name, section, cfg_source());
 
316
        free(s);
 
317
        return -1;
 
318
    }
 
319
 
 
320
    Format = NIL;
 
321
 
 
322
#ifdef WITH_PPM
 
323
    if (strcmp(s, "PPM") == 0) {
 
324
        Format = PPM;
 
325
    }
 
326
#endif
 
327
 
 
328
#ifdef WITH_PNG
 
329
    if (strcmp(s, "PNG") == 0) {
 
330
        Format = PNG;
 
331
    }
 
332
#endif
 
333
 
 
334
    if (Format == NIL) {
 
335
        error("%s: bad %s.Format '%s' from %s", Name, section, s, cfg_source());
 
336
        free(s);
 
337
        return -1;
 
338
    }
 
339
    free(s);
 
340
 
 
341
    /* read display size from config */
 
342
    if (sscanf(s = cfg_get(section, "Size", "120x32"), "%dx%d", &DCOLS, &DROWS) != 2 || DCOLS < 1 || DROWS < 1) {
 
343
        error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source());
 
344
        free(s);
 
345
        return -1;
 
346
    }
 
347
    free(s);
 
348
 
 
349
    if (sscanf(s = cfg_get(section, "font", "5x8"), "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) {
 
350
        error("%s: bad %s.Font '%s' from %s", Name, section, s, cfg_source());
 
351
        free(s);
 
352
        return -1;
 
353
    }
 
354
    free(s);
 
355
 
 
356
    if (sscanf(s = cfg_get(section, "pixel", "4+1"), "%d+%d", &pixel, &pgap) != 2 || pixel < 1 || pgap < 0) {
 
357
        error("%s: bad %s.Pixel '%s' from %s", Name, section, s, cfg_source());
 
358
        free(s);
 
359
        return -1;
 
360
    }
 
361
    free(s);
 
362
 
 
363
    if (sscanf(s = cfg_get(section, "gap", "-1x-1"), "%dx%d", &cgap, &rgap) != 2 || cgap < -1 || rgap < -1) {
 
364
        error("%s: bad %s.Gap '%s' from %s", Name, section, s, cfg_source());
 
365
        free(s);
 
366
        return -1;
 
367
    }
 
368
    free(s);
 
369
 
 
370
    if (rgap < 0)
 
371
        rgap = pixel + pgap;
 
372
    if (cgap < 0)
 
373
        cgap = pixel + pgap;
 
374
 
 
375
    if (cfg_number(section, "border", 0, 0, -1, &border) < 0)
 
376
        return -1;
 
377
 
 
378
    s = cfg_get(section, "basecolor", "000000ff");
 
379
    if (color2RGBA(s, &BC) < 0) {
 
380
        error("%s: ignoring illegal color '%s'", Name, s);
 
381
    }
 
382
    free(s);
 
383
 
 
384
    drv_IMG_FB = malloc(DCOLS * DROWS * sizeof(*drv_IMG_FB));
 
385
    if (drv_IMG_FB == NULL) {
 
386
        error("%s: framebuffer could not be allocated: malloc() failed", Name);
 
387
        return -1;
 
388
    }
 
389
 
 
390
    for (i = 0; i < DCOLS * DROWS; i++) {
 
391
        drv_IMG_FB[i] = BC;
 
392
    }
 
393
 
 
394
    dimx = DCOLS * pixel + (DCOLS - 1) * pgap + (DCOLS / XRES - 1) * cgap;
 
395
    dimy = DROWS * pixel + (DROWS - 1) * pgap + (DROWS / YRES - 1) * rgap;
 
396
 
 
397
 
 
398
    /* initially flush the image to a file */
 
399
    drv_IMG_flush();
 
400
 
 
401
    /* regularly flush the image to a file */
 
402
    /* Fixme: make 100msec configurable */
 
403
    timer_add(drv_IMG_timer, NULL, 100, 0);
 
404
 
 
405
 
 
406
    return 0;
 
407
}
 
408
 
 
409
 
 
410
 
 
411
/****************************************/
 
412
/***            plugins               ***/
 
413
/****************************************/
 
414
 
 
415
/* none at the moment... */
 
416
 
 
417
 
 
418
/****************************************/
 
419
/***        exported functions        ***/
 
420
/****************************************/
 
421
 
 
422
 
 
423
/* list models */
 
424
int drv_IMG_list(void)
 
425
{
 
426
#ifdef WITH_PPM
 
427
    printf("PPM ");
 
428
#endif
 
429
#ifdef WITH_PNG
 
430
    printf("PNG ");
 
431
#endif
 
432
    return 0;
 
433
}
 
434
 
 
435
 
 
436
/* initialize driver & display */
 
437
int drv_IMG_init(const char *section, const __attribute__ ((unused))
 
438
                 int quiet)
 
439
{
 
440
    int ret;
 
441
 
 
442
    info("%s: %s", Name, "$Rev: 840 $");
 
443
 
 
444
    /* real worker functions */
 
445
    drv_generic_graphic_real_blit = drv_IMG_blit;
 
446
 
 
447
    /* start display */
 
448
    if ((ret = drv_IMG_start(section)) != 0)
 
449
        return ret;
 
450
 
 
451
    /* initialize generic graphic driver */
 
452
    if ((ret = drv_generic_graphic_init(section, Name)) != 0)
 
453
        return ret;
 
454
 
 
455
    /* register plugins */
 
456
    /* none at the moment... */
 
457
 
 
458
 
 
459
    return 0;
 
460
}
 
461
 
 
462
 
 
463
/* close driver & display */
 
464
int drv_IMG_quit(const __attribute__ ((unused))
 
465
                 int quiet)
 
466
{
 
467
 
 
468
    info("%s: shutting down.", Name);
 
469
    drv_generic_graphic_quit();
 
470
 
 
471
    if (drv_IMG_FB) {
 
472
        free(drv_IMG_FB);
 
473
        drv_IMG_FB = NULL;
 
474
    }
 
475
 
 
476
    return (0);
 
477
}
 
478
 
 
479
 
 
480
DRIVER drv_Image = {
 
481
    .name = Name,
 
482
    .list = drv_IMG_list,
 
483
    .init = drv_IMG_init,
 
484
    .quit = drv_IMG_quit,
 
485
};