2
* cacaview image viewer for libcaca
3
* Copyright (c) 2003 Sam Hocevar <sam@zoy.org>
6
* $Id: cacaview.c 257 2004-01-23 09:20:39Z sam $
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30
#if defined(HAVE_IMLIB2_H)
36
#if defined(HAVE_SLEEP)
46
#define STATUS_DITHERING 1
47
#define STATUS_ANTIALIASING 2
48
#define STATUS_BACKGROUND 3
50
#define ZOOM_FACTOR 1.08f
55
static void print_status(void);
56
static void print_help(int, int);
57
static void set_zoom(int);
58
static void load_image(char const *);
59
static void unload_image(void);
60
static void draw_checkers(int, int, int, int);
61
#if !defined(HAVE_IMLIB2_H)
62
static int freadint(FILE *);
63
static int freadshort(FILE *);
64
static int freadchar(FILE *);
68
#if defined(HAVE_IMLIB2_H)
69
Imlib_Image image = NULL;
72
struct caca_bitmap *bitmap = NULL;
73
unsigned int w, h, depth, bpp, rmask, gmask, bmask, amask;
74
#if !defined(HAVE_IMLIB2_H)
75
unsigned int red[256], green[256], blue[256], alpha[256];
78
float zoomtab[ZOOM_MAX + 1];
79
float xfactor = 1.0, yfactor = 1.0, dx = 0.5, dy = 0.5;
80
int zoom = 0, fullscreen = 0, mode, ww, wh;
82
int main(int argc, char **argv)
84
int quit = 0, update = 1, help = 0, status = 0;
88
int current = 0, items = 0, opts = 1;
91
/* Initialise libcaca */
94
fprintf(stderr, "%s: unable to initialise libcaca\n", argv[0]);
98
/* Set the window title */
99
caca_set_window_title("cacaview");
101
ww = caca_get_width();
102
wh = caca_get_height();
104
/* Fill the zoom table */
106
for(i = 0; i < ZOOM_MAX; i++)
107
zoomtab[i + 1] = zoomtab[i] * 1.08;
109
/* Load items into playlist */
110
for(i = 1; i < argc; i++)
112
/* Skip options except after `--' */
113
if(opts && argv[i][0] == '-')
115
if(argv[i][1] == '-' && argv[i][2] == '\0')
120
/* Add argv[i] to the list */
122
list = realloc(list, (items + 1) * sizeof(char *));
124
list = malloc(sizeof(char *));
125
list[items] = argv[i];
134
unsigned int const event_mask = CACA_EVENT_KEY_PRESS
136
| CACA_EVENT_MOUSE_PRESS;
137
unsigned int event, new_status = 0, new_help = 0;
140
event = caca_get_event(event_mask);
142
event = caca_wait_event(event_mask);
146
if(event & CACA_EVENT_MOUSE_PRESS)
148
if((event & 0x00ffffff) == 1)
150
if(items) current = (current + 1) % items;
153
else if((event & 0x00ffffff) == 2)
155
if(items) current = (items + current - 1) % items;
159
else if(event & CACA_EVENT_KEY_PRESS) switch(event & 0x00ffffff)
163
if(items) current = (current + 1) % items;
168
if(items) current = (items + current - 1) % items;
173
fullscreen = ~fullscreen;
178
i = 1 + caca_get_feature(CACA_BACKGROUND);
179
if(i > CACA_BACKGROUND_MAX) i = CACA_BACKGROUND_MIN;
181
new_status = STATUS_BACKGROUND;
185
i = -1 + caca_get_feature(CACA_BACKGROUND);
186
if(i < CACA_BACKGROUND_MIN) i = CACA_BACKGROUND_MAX;
188
new_status = STATUS_BACKGROUND;
192
i = 1 + caca_get_feature(CACA_ANTIALIASING);
193
if(i > CACA_ANTIALIASING_MAX) i = CACA_ANTIALIASING_MIN;
195
new_status = STATUS_ANTIALIASING;
199
i = -1 + caca_get_feature(CACA_ANTIALIASING);
200
if(i < CACA_ANTIALIASING_MIN) i = CACA_ANTIALIASING_MAX;
202
new_status = STATUS_ANTIALIASING;
206
i = 1 + caca_get_feature(CACA_DITHERING);
207
if(i > CACA_DITHERING_MAX) i = CACA_DITHERING_MIN;
209
new_status = STATUS_DITHERING;
213
i = -1 + caca_get_feature(CACA_DITHERING);
214
if(i < CACA_DITHERING_MIN) i = CACA_DITHERING_MAX;
216
new_status = STATUS_DITHERING;
235
if(yfactor > 1.0) dy -= PAD_STEP / yfactor;
236
if(dy < 0.0) dy = 0.0;
242
if(yfactor > 1.0) dy += PAD_STEP / yfactor;
243
if(dy > 1.0) dy = 1.0;
249
if(xfactor > 1.0) dx -= PAD_STEP / xfactor;
250
if(dx < 0.0) dx = 0.0;
256
if(xfactor > 1.0) dx += PAD_STEP / xfactor;
257
if(dx > 1.0) dx = 1.0;
269
else if(event == CACA_EVENT_RESIZE)
272
ww = caca_get_width();
273
wh = caca_get_height();
278
if(status || new_status)
284
event = caca_get_event(CACA_EVENT_KEY_PRESS);
290
int len = strlen(" Loading `%s'... ") + strlen(list[current]);
295
buffer = malloc(len);
297
sprintf(buffer, " Loading `%s'... ", list[current]);
299
caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE);
300
caca_putstr((ww - strlen(buffer)) / 2, wh / 2, buffer);
302
ww = caca_get_width();
303
wh = caca_get_height();
306
load_image(list[current]);
309
/* Reset image-specific runtime variables */
321
caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE);
322
caca_printf(ww / 2 - 5, wh / 2, " No image. ");
326
#if defined(HAVE_IMLIB2_H)
327
# define ERROR_STRING " Error loading `%s'. "
329
# define ERROR_STRING " Error loading `%s'. Only BMP is supported. "
332
int len = strlen(ERROR_STRING) + strlen(list[current]);
337
buffer = malloc(len);
339
sprintf(buffer, ERROR_STRING, list[current]);
341
caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE);
342
caca_putstr((ww - strlen(buffer)) / 2, wh / 2, buffer);
347
float xdelta, ydelta;
350
y = fullscreen ? 0 : 1;
351
height = fullscreen ? wh : wh - 3;
353
xdelta = (xfactor > 1.0) ? dx : 0.5;
354
ydelta = (yfactor > 1.0) ? dy : 0.5;
356
draw_checkers(ww * (1.0 - xfactor) / 2,
357
y + height * (1.0 - yfactor) / 2,
358
ww * (1.0 + xfactor) / 2,
359
y + height * (1.0 + yfactor) / 2);
361
caca_draw_bitmap(ww * (1.0 - xfactor) * xdelta,
362
y + height * (1.0 - yfactor) * ydelta,
363
ww * (xdelta + (1.0 - xdelta) * xfactor),
364
y + height * (ydelta + (1.0 - ydelta) * yfactor),
372
caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
375
case STATUS_ANTIALIASING:
376
caca_printf(0, wh - 1, "Antialiasing: %s",
377
caca_get_feature_name(caca_get_feature(CACA_ANTIALIASING)));
379
case STATUS_DITHERING:
380
caca_printf(0, wh - 1, "Dithering: %s",
381
caca_get_feature_name(caca_get_feature(CACA_DITHERING)));
383
case STATUS_BACKGROUND:
384
caca_printf(0, wh - 1, "Background: %s",
385
caca_get_feature_name(caca_get_feature(CACA_BACKGROUND)));
392
print_help(ww - 25, 2);
406
static void print_status(void)
408
caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE);
409
caca_draw_line(0, 0, ww - 1, 0, ' ');
410
caca_draw_line(0, wh - 2, ww - 1, wh - 2, '-');
411
caca_putstr(0, 0, "q:Quit np:Next/Prev +-x:Zoom "
412
"hjkl:Move d:Dithering a:Antialias");
413
caca_putstr(ww - strlen("?:Help"), 0, "?:Help");
414
caca_printf(3, wh - 2, "cacaview %s", VERSION);
415
caca_printf(ww - 14, wh - 2, "(zoom: %s%i)", zoom > 0 ? "+" : "", zoom);
417
caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_BLACK);
418
caca_draw_line(0, wh - 1, ww - 1, wh - 1, ' ');
421
static void print_help(int x, int y)
423
static char const *help[] =
428
" ---------------------- ",
430
" arrows: move view ",
431
" ---------------------- ",
432
" a: antialiasing method ",
433
" d: dithering method ",
434
" b: background mode ",
435
" ---------------------- ",
443
caca_set_color(CACA_COLOR_WHITE, CACA_COLOR_BLUE);
445
for(i = 0; help[i]; i++)
446
caca_putstr(x, y + i, help[i]);
449
static void set_zoom(int new_zoom)
455
if(zoom > ZOOM_MAX) zoom = ZOOM_MAX;
456
if(zoom < -ZOOM_MAX) zoom = -ZOOM_MAX;
458
ww = caca_get_width();
459
height = fullscreen ? wh : wh - 3;
461
xfactor = (zoom < 0) ? 1.0 / zoomtab[-zoom] : zoomtab[zoom];
462
yfactor = xfactor * ww / height * h / w
463
* caca_get_height() / caca_get_width()
464
* caca_get_window_width() / caca_get_window_height();
466
if(yfactor > xfactor)
469
xfactor = tmp * tmp / yfactor;
474
static void unload_image(void)
476
#if defined(HAVE_IMLIB2_H)
487
caca_free_bitmap(bitmap);
491
static void load_image(char const *name)
493
#if defined(HAVE_IMLIB2_H)
494
/* Load the new image */
495
image = imlib_load_image(name);
500
imlib_context_set_image(image);
501
pixels = (char *)imlib_image_get_data_for_reading_only();
502
w = imlib_image_get_width();
503
h = imlib_image_get_height();
511
/* Create the libcaca bitmap */
512
bitmap = caca_create_bitmap(bpp, w, h, depth * w,
513
rmask, gmask, bmask, amask);
521
/* Try to load a BMP file */
523
unsigned int i, colors, offset, tmp, planes;
525
fp = fopen(name, "rb");
529
if(freadshort(fp) != 0x4d42)
535
freadint(fp); /* size */
536
freadshort(fp); /* reserved 1 */
537
freadshort(fp); /* reserved 2 */
539
offset = freadint(fp);
541
tmp = freadint(fp); /* header size */
546
planes = freadshort(fp);
547
bpp = freadshort(fp);
549
tmp = freadint(fp); /* compression */
556
freadint(fp); /* sizeimage */
557
freadint(fp); /* xpelspermeter */
558
freadint(fp); /* ypelspermeter */
559
freadint(fp); /* biclrused */
560
freadint(fp); /* biclrimportantn */
562
colors = (offset - 54) / 4;
563
for(i = 0; i < colors && i < 256; i++)
565
blue[i] = freadchar(fp) * 16;
566
green[i] = freadchar(fp) * 16;
567
red[i] = freadchar(fp) * 16;
576
planes = freadshort(fp);
577
bpp = freadshort(fp);
579
colors = (offset - 26) / 3;
580
for(i = 0; i < colors && i < 256; i++)
582
blue[i] = freadchar(fp);
583
green[i] = freadchar(fp);
584
red[i] = freadchar(fp);
594
/* Fill the rest of the palette */
595
for(i = colors; i < 256; i++)
596
blue[i] = green[i] = red[i] = alpha[i] = 0;
598
depth = (bpp + 7) / 8;
601
if(!w || w > 0x10000 || !h || h > 0x10000 || planes != 1 /*|| bpp != 24*/)
607
/* Allocate the pixel buffer */
608
pixels = malloc(w * h * depth);
615
memset(pixels, 0, w * h * depth);
617
/* Read the bitmap data */
620
unsigned int j, k, bits = 0;
625
for(j = 0; j < w; j++)
630
pixels[w * i * depth + j] =
631
(bits >> ((k & ~0xf) + 0xf - (k & 0xf))) & 0x1;
635
for(j = 0; j < w; j++)
640
pixels[w * i * depth + j] =
641
(bits >> (4 * ((k & ~0x1) + 0x1 - (k & 0x1)))) & 0xf;
645
/* Works for 8bpp, but also for 16, 24 etc. */
646
fread(pixels + w * i * depth, w * depth, 1, fp);
647
/* Pad reads to 4 bytes */
648
tmp = (w * depth) % 4;
664
case 2: /* XXX: those are the 16 bits values */
673
rmask = gmask = bmask = amask = 0;
679
/* Create the libcaca bitmap */
680
bitmap = caca_create_bitmap(bpp, w, h, depth * w,
681
rmask, gmask, bmask, amask);
690
caca_set_bitmap_palette(bitmap, red, green, blue, alpha);
694
static void draw_checkers(int x1, int y1, int x2, int y2)
698
if(x2 + 1 > (int)caca_get_width()) x2 = caca_get_width() - 1;
699
if(y2 + 1 > (int)caca_get_height()) y2 = caca_get_height() - 1;
701
for(yn = y1 > 0 ? y1 : 0; yn <= y2; yn++)
702
for(xn = x1 > 0 ? x1 : 0; xn <= x2; xn++)
704
if((((xn - x1) / 5) ^ ((yn - y1) / 3)) & 1)
705
caca_set_color(CACA_COLOR_LIGHTGRAY, CACA_COLOR_DARKGRAY);
707
caca_set_color(CACA_COLOR_DARKGRAY, CACA_COLOR_LIGHTGRAY);
708
caca_putchar(xn, yn, ' ');
712
#if !defined(HAVE_IMLIB2_H)
713
static int freadint(FILE *fp)
715
unsigned char buffer[4];
716
fread(buffer, 4, 1, fp);
717
return ((int)buffer[3] << 24) | ((int)buffer[2] << 16)
718
| ((int)buffer[1] << 8) | ((int)buffer[0]);
721
static int freadshort(FILE *fp)
723
unsigned char buffer[2];
724
fread(buffer, 2, 1, fp);
725
return ((int)buffer[1] << 8) | ((int)buffer[0]);
728
static int freadchar(FILE *fp)
730
unsigned char buffer;
731
fread(&buffer, 1, 1, fp);