pkg://vimage-1.1.tar.gz:38196/vimage.c
downloads
/*
* $Id: vimage.c,v 1.6 1995/09/16 14:01:57 traister Exp traister $
* vimage - an SVGA picture viewer for Linux using VGAlib 1.3
* Copyright (c) 1995, Joseph J. Traister
*
* $Log: vimage.c,v $
* Revision 1.6 1995/09/16 14:01:57 traister
* Rewrote error reporting throughout.
* Added file type table to facilitate adding new image types.
*
* Revision 1.5 1995/09/03 02:14:54 traister
* Added ReadFile() to generically read an image.
*
* Revision 1.4 1995/08/06 03:05:55 traister
* Added ESC exit to final wait loop in SlideShow()
*
* Revision 1.3 1995/07/30 19:20:47 traister
* Updated copyright prior to first public release
*
* Revision 1.2 1995/05/13 22:40:17 traister
* Added "break" in slide show when ESC hit.
*
* Revision 1.1 1995/05/13 01:40:52 traister
* Initial revision
*
*/
/* 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 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <vga.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <values.h>
#include <getopt.h>
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include "vimage.h"
/*
Initial size of, and increment to, fnames array size during
slide file read
*/
#define NAME_INC 100
#ifdef NCURSES_SUPPORT
#define OPTSTRING "m:l:d:qxra2fs:Rcvit"
#else
#define OPTSTRING "m:l:d:qxra2fs:Rvit"
#endif
char progname[PATH_MAX], modename[256]="", **fnames=NULL;
char errmsg[512];
int quiet=0, automode=0, pictime=6, twopass=0, floyd=0, slide=0, reverse=0;
int interact=0, notruecolor=0;
unsigned loopcount=1, printstats=0;
#ifdef NCURSES_SUPPORT
int filesel=0;
#endif
FTYPE ftypes[] = {
{ "", NULL, NULL }, /* dummy entry. 0= invalid file */
#ifdef JPEG_SUPPORT
{ "JPEG", ReadJPEGHead, ReadJPEG },
#endif
{ "TIFF", ReadTIFFHead, ReadTIFF },
{ "Targa", ReadTargaHead, ReadTarga },
{ "Sun Rasterfile", ReadRasterfileHead, ReadRasterfile },
{ "PNM", ReadPNMHead, ReadPNM },
{ "GIF", ReadGIFHead, ReadGIF }
};
#define NR_FTYPES (sizeof(ftypes)/sizeof(FTYPE)-1)
int randcompare(const void*, const void*);
int ReadSlideFile(char*);
int Interact(char**, int);
int main(int argc, char **argv)
{
char temp[PATH_MAX], c;
extern int optind;
extern char *optarg;
int fc=0, i, errval=0, randfiles=0, pipe_input=0, filetype;
FILE *fpin;
IMAGE image, newimage;
SetID();
strcpy(progname, argv[0]);
optind = 1;
while ((i=getopt(argc, argv, OPTSTRING)) != EOF) {
switch (i) {
case 't':
notruecolor = 1;
break;
case 'l':
loopcount = atoi(optarg);
break;
case 'd':
pictime = atoi(optarg);
break;
case 'q':
quiet = 1;
break;
case 'x':
printstats = 1;
break;
case 'r':
reverse = 1;
break;
case 'a':
automode = 1;
break;
case 'm':
strcpy(modename, optarg);
break;
case '2':
twopass = 1;
break;
case 'f':
floyd = 1;
break;
case 'R':
randfiles=1;
break;
case 's':
fc = ReadSlideFile(optarg);
if (fc < 0) {
fprintf(stderr, "%s: %s\n", progname, errmsg);
return -1;
}
slide = 1;
break;
case 'v':
printf("%s: version %s\n", progname, VERSION);
return 0;
case 'i':
interact=1;
break;
#ifdef NCURSES_SUPPORT
case 'c':
filesel=1;
break;
#endif
case '?':
default:
errval++;
}
}
if (optind == argc && !slide) {
if (!isatty(STDIN_FILENO)) {
pipe_input = 1;
sprintf(temp, "/tmp/vimage.%i", getpid());
if (!(fnames = (char**)malloc(sizeof(char*)))) {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
if (!(fnames[0] = (char*)malloc(strlen(temp)+1))) {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
strcpy(fnames[0], temp);
if (!(fpin = fopen(temp, "w"))) {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
while ((i=getchar()) != EOF)
fputc(i, fpin);
fc = 1;
fclose(fpin);
} else
errval++;
}
if (errval) {
fprintf(stderr,
"Vimage v"VERSION" - Copyright (c) 1995, Joe Traister\n"
"Usage: %s [options] [-s slide | file ... | < filename]\n"
"Options:\n"
" -R Display pictures in random order\n"
" -a Automatically choose video mode based on picture "
"size\n"
" and number of colors\n"
#ifdef NCURSES_SUPPORT
" -c Use full-screen file selector\n"
#endif
" -f Add Floyd-Steinberg dithering to Heckbert median "
"cut\n"
" -q Quiet, do not display or break on file read errors\n"
" -r Show pictures in reverse order\n"
" -t Do not use 24-bit video modes (for Cirrus Logic "
"5426/28)\n"
" -x No picture display, list image statistics instead\n"
" -2 Use Heckbert median cut (2-pass) color palette"
" computation\n"
" -d n Delay {n} seconds between pictures (Default=6)\n"
" -l n Loop through pictures {n} times (Default=1)\n"
" -m mode Use video mode {mode}\n"
" -s slide Read filenames from file {slide}\n"
" -v Print version and quit\n"
" Shows "
#ifdef JPEG_SUPPORT
"JPEG, "
#endif
"Targa, PPM, PBM, PGM, GIF, SunRaster and TIFF images\n",
progname);
return -1;
}
if (!slide && !pipe_input) {
fc = argc-optind;
if (!(fnames = (char**)malloc(sizeof(char*)*fc))) {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
for (i=0; i < fc; i++) {
if (!(fnames[i] = (char*)malloc(strlen(argv[i+optind])+1))) {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
strcpy(fnames[i], argv[i+optind]);
}
}
if (printstats) {
for (i=0; i < fc; i++) {
if (!(fpin = fopen(fnames[i], "r")))
if (quiet)
continue;
else {
fprintf(stderr, "%s: %s: %s\n", progname, strerror(errno), temp);
return -1;
}
filetype = GetFileHead(fpin, &image);
fclose(fpin);
if (filetype < 0) {
fprintf(stderr, "%s: %s: %s\n", progname, errmsg, fnames[i]);
return -1;
} else if (!filetype)
printf("%s: Unknown file type: %s\n", progname, fnames[i]);
else {
printf("%s: %ix%ix%i %s\n", fnames[i], image.width, image.height,
image.palsize > 0 ? image.palsize : 1<<(-image.palsize),
ftypes[filetype].name);
}
}
return 0;
}
#ifdef NCURSES_SUPPORT
if (filesel)
return fileSelector(fnames, fc);
#endif
if (InitVGA(modename)) {
fprintf(stderr, "%s: %s\n", progname, errmsg);
return -1;
}
if (fc == 1) {
pictime = 0;
if (!pipe_input)
printf("%s: Reading file: %s\n", progname, fnames[0]);
if (ReadFile(fnames[0], &image)) {
fprintf(stderr, "%s: %s\n", progname, errmsg);
return -1;
}
SetModeInfo(&image);
if (image.width > modeinfo->width || image.height > modeinfo->height) {
if (!pipe_input)
printf("%s: Scaling...\n", progname);
if (Scale(&image, &newimage, modeinfo->width, modeinfo->height)) {
fprintf(stderr, "%s: %s: %s\n", progname, errmsg, fnames[0]);
return -1;
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
if (modeinfo->bytesperpixel == 1 && image.palsize < -8) {
if (!pipe_input)
printf("%s: Color quantizing...\n", progname);
if (twopass) {
if (HeckbertMedianCut(&image, &newimage)) {
fprintf(stderr, "%s: %s: %s\n", progname, errmsg, fnames[0]);
return -1;
}
} else {
if (MapToCube(&image, &newimage)) {
fprintf(stderr, "%s: %s: %s\n", progname, errmsg, fnames[0]);
return -1;
}
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
SetVideoMode();
if (DisplayImage(&image)) {
VGAShutdown();
fprintf(stderr, "%s: %s: %s\n", progname, errmsg, fnames[0]);
return -1;
}
do {
c = vga_getch();
} while (c != '\n' && c != 'Q' && c != 'q' && c != 0x1b);
free(image.bits);
VGAShutdown();
if (pipe_input)
unlink(fnames[0]);
} else if (interact) {
if (Interact(fnames, fc)) {
fprintf(stderr, "%s: %s\n", progname, errmsg);
return -1;
}
} else {
if (randfiles) {
srand(getpid() ^ time(0));
qsort(fnames, fc, sizeof(char*), randcompare);
}
if (Slideshow(fnames, fc)) {
fprintf(stderr, "%s: %s\n", progname, errmsg);
return -1;
}
}
return 0;
}
int Interact(char **fnames, int fc)
{
int curr=0, quit=0, cont, c;
IMAGE image, newimage;
do {
image.bits=NULL;
if (ReadFile(fnames[curr], &image))
if (quiet)
continue;
else
return -1;
SetModeInfo(&image);
if (image.width > modeinfo->width || image.height > modeinfo->height) {
if (Scale(&image, &newimage, modeinfo->width, modeinfo->height)) {
free(image.bits);
if (quiet)
continue;
else {
strcat(errmsg, ": ");
strcat(errmsg, fnames[curr]);
return -1;
}
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
if (modeinfo->bytesperpixel == 1 && image.palsize < -8) {
if (twopass) {
if (HeckbertMedianCut(&image, &newimage)) {
free(image.bits);
if (quiet)
continue;
else {
strcat(errmsg, ": ");
strcat(errmsg, fnames[curr]);
return -1;
}
}
} else {
if (MapToCube(&image, &newimage)) {
free(image.bits);
if (quiet)
continue;
else {
strcat(errmsg, ": ");
strcat(errmsg, fnames[curr]);
return -1;
}
}
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
SetVideoMode();
if (DisplayImage(&image)) {
VGAShutdown();
free(image.bits);
strcat(errmsg, ": ");
strcat(errmsg, fnames[curr]);
return -1;
}
free(image.bits);
cont=0;
do {
switch (c=vga_getkey()) {
case ' ':
if (curr < fc-1) {
cont = 1;
curr++;
}
break;
case 0x7f: /* backspace key */
if (curr > 0) {
cont = 1;
curr--;
}
break;
case 'q':
case 'Q':
case '\n':
case 0x1b:
quit=1;
}
} while (!cont && !quit);
} while (!quit);
return 0;
}
int Slideshow(char **fnames, int fc)
{
int i, loop=0, timer;
IMAGE image, newimage;
timer=0;
if (!reverse)
i = 0;
else
i = fc-1;
while (1) {
image.bits = NULL;
if (!ReadFile(fnames[i], &image)) {
SetModeInfo(&image);
if (image.width > modeinfo->width || image.height > modeinfo->height) {
if (Scale(&image, &newimage, modeinfo->width, modeinfo->height)) {
free(image.bits);
if (quiet)
goto next;
else {
VGAShutdown();
strcat(errmsg, ": ");
strcat(errmsg, fnames[i]);
return -1;
}
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
if (modeinfo->bytesperpixel == 1 && image.palsize < -8) {
if (twopass) {
if (HeckbertMedianCut(&image, &newimage)) {
free(image.bits);
if (quiet)
goto next;
else {
VGAShutdown();
strcat(errmsg, ": ");
strcat(errmsg, fnames[i]);
return -1;
}
}
} else {
if (MapToCube(&image, &newimage)) {
free(image.bits);
if (quiet)
goto next;
else {
VGAShutdown();
strcat(errmsg, ": ");
strcat(errmsg, fnames[i]);
return -1;
}
}
}
free(image.bits);
memcpy(&image, &newimage, sizeof(IMAGE));
}
if (timer)
do {
if (vga_getkey() == 0x1b) { /* ESC exits slideshow */
VGAShutdown();
return 0;
}
} while (pictime > (time(0)-timer));
SetVideoMode();
if (DisplayImage(&image)) {
free(image.bits);
VGAShutdown();
return -1;
}
free(image.bits);
timer = time(0);
} else
if (!quiet)
return -1;
next:
if (!reverse) {
i++;
if (i >= fc) {
loop++;
if (loop >= loopcount)
break;
i = 0;
}
} else {
i--;
if (i < 0) {
loop++;
if (loop >= loopcount)
break;
i = fc-1;
}
}
}
timer = time(0);
while (time(0)-timer < pictime)
if (vga_getkey() == 0x1b)
break;
VGAShutdown();
return 0;
}
int GetFileHead(FILE *fpin, IMAGE *image)
{
int i, status;
for (i=NR_FTYPES; i > 0; --i) {
status = ftypes[i].rhead(fpin, image);
if (status < 0)
return -1;
if (status)
return i;
rewind(fpin);
}
return 0;
}
int ReadFile(char *filename, IMAGE *image)
{
FILE *fpin;
int filetype;
if (!(fpin = fopen(filename, "r"))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, filename);
return -1;
}
if ((filetype=GetFileHead(fpin, image)) < 0) {
strcat(errmsg, ": ");
strcat(errmsg, filename);
fclose(fpin);
return -1;
}
if (!filetype) {
strcpy(errmsg, "Unknown file type: ");
strcat(errmsg, filename);
fclose(fpin);
return -1;
}
if (ftypes[filetype].rfile(fpin, image)) {
fclose(fpin);
strcat(errmsg, ": ");
strcat(errmsg, filename);
return -1;
}
fclose(fpin);
return 0;
}
int randcompare(const void *arg1, const void *arg2)
{
if (rand() < RAND_MAX/2)
return 1;
else
return -1;
}
int ReadSlideFile(char *slidefile)
{
int fc=0, size=NAME_INC;
FILE *fpin;
char temp[PATH_MAX], *chp;
if (!(fpin = fopen(slidefile, "r"))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, slidefile);
return -1;
}
if (!(fnames = (char**)malloc(sizeof(char*)*size))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, slidefile);
return -1;
}
while (!feof(fpin)) {
fgets(temp, PATH_MAX, fpin);
chp = strchr(temp, '#');
if (chp)
*chp = '\0';
if (!strlen(temp))
continue;
for (chp=temp+strlen(temp)-1; chp >= temp; chp--)
if (isgraph(*chp)) {
*(chp+1) = '\0';
break;
}
if (chp < temp)
continue;
for (chp=temp; chp-temp < strlen(temp); chp++)
if (isgraph(*chp))
break;
if (chp != temp)
memmove(temp, chp, strlen(temp)-(chp-temp)+1);
if (fc >= size) {
size += NAME_INC;
if (!(fnames = (char**)realloc(fnames, sizeof(char*)*size))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, slidefile);
return -1;
}
}
if (!(fnames[fc] = (char*)malloc(strlen(temp)+1))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, slidefile);
return -1;
}
strcpy(fnames[fc], temp);
temp[0] = '\0';
fc++;
}
if (size != fc) {
if (!(fnames = realloc(fnames, sizeof(char*)*fc))) {
strcpy(errmsg, strerror(errno));
strcat(errmsg, ": ");
strcat(errmsg, slidefile);
return -1;
}
}
if (!fc) {
strcpy(errmsg, "No slide file names found: ");
strcat(errmsg, slidefile);
return -1;
}
fclose(fpin);
return fc;
}