Output filters for xscanimage: a simple attempt

Stefan Illy (stefan.illy@itp.fzk.de)
Tue, 10 Nov 1998 10:13:23 +0100 (MET)

Hello,

I wondered why there is no possibility to use other output formats than
PNM in xscanimage. So I decided to implement output filters for other
formats in a simple way without changing too much of xscanimage.

This was done by replacing the `fopen' and `fclose' commands in
xscanimage.c by functions called `pfopen' and `pfclose'. Both functions
are implemented in `pfopen.c' appended below. Please look at the
comments in this file for more details, it should be not too complicated.

The conversion can be done by `netpbm' filters, ImageMagick's `convert'
command or `cjpeg'. Compression using `gzip' is also possible.

If you want to test it, replace `fopen' and `fclose' in xscanimage.c
by `pfopen' and `pfclose', respectively. Don't forget to provide
prototypes for both functions. Provide pfopen.c in the `frontend' path
and add an entry for pfopen.o in the corresponding Makefile.

I tested it both with the 0.74 and the pre-1.00 version and had no
problems (on Linux, kernel 2.0.35, libc5).

Please tell me what you think about this attempt, if it worked for you
and what could be done in a better way.

Stefan

----8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<---
/*
* pfopen.c: A simple way to provide output filters for xscanimage.
*
* Author: Stefan Illy <stefan.illy@itp.fzk.de>
*
*/

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#define STRLEN 256

/*
* List of output filters.
* This should be provided in a configuration file (e.g. `filters.conf')
*/
char* filter_list[] = {
".eps: convert pnm:- eps2:-",
".eps.gz: convert pnm:- eps2:- | gzip",
".ps: convert pnm:- ps2:-",
".ps.gz: convert pnm:- ps2:- | gzip",
".jpg: cjpeg -quality 75",
".png: pnmtopng",
".pnm.gz: gzip",
NULL};

/*
* Returns one if `str' ends with `expr', otherwise zero.
*/
int
strends(const char* str, const char* expr)
{
char* pos;
if ((pos = strstr(str, expr)) == NULL) return 0;
if (strlen(str) - strlen(expr) == (int)(pos - str)) return 1; else return 0;
}

/*
* pfopen: replacement for fopen in `xscanimage.c'.
*
* If `path' starts with the pipe symbol `|' or the extension of the
* file name is in `filter_list', popen will be used instead of
* fopen.
*
*/
FILE*
pfopen(const char* path, char* mode)
{
FILE* stream;
char filter[STRLEN] = "";

if (path[0] == '|') /* Output filter directly specified. */
{
strcpy(filter, &path[1]);
}
else /* Search filter_list for extension. */
{
int i;
for (i = 0; filter_list[i] != NULL; i++)
{
char* pos;
if ((pos = strchr(filter_list[i], ':')) != NULL)
{
char ext[STRLEN] = "";
strncpy(ext, filter_list[i], (int)(pos - filter_list[i]));
if (strends(path, ext))
{
strcpy(filter, pos + 1);
strcat(filter, " > ");
strcat(filter, path);
break;
}
}
}
}

if (strcmp(filter, "") == 0)
{
fprintf(stderr, "pfopen: using fopen(%s).\n", path);
stream = fopen(path, mode);
}
else
{
fprintf(stderr, "pfopen: using popen(%s).\n", filter);
stream = popen(filter, mode);
}

return stream;
}

/*
* pfclose: replacement for fclose in `xscanimage.c'.
*
* Uses fstat to determine if `stream' belongs to a regular file.
* If this is not the case, pclose will be used instead of
* fclose.
*
* Maybe there are better (and more secure) methods to do this.
*/
int
pfclose(FILE* stream)
{
struct stat statinfo;

if (fstat(fileno(stream), &statinfo) != 0)
{
fprintf(stderr, "pfclose: fstat was not successful, using fclose.\n");
return fclose(stream);
}

if (S_ISREG(statinfo.st_mode))
{
fprintf(stderr, "pfclose: S_ISREG==true, using fclose.\n");
return fclose(stream);
}
else
{
fprintf(stderr, "pfclose: S_ISREG==false, using pclose.\n");
return pclose(stream);
}
}
----8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<---

-- 
Stefan Illy                     |  Institut fuer Technische Physik (ITP)
e-mail: stefan.illy@itp.fzk.de  |  Forschungszentrum Karlsruhe GmbH
phone:  (+49) 07247/82-4165     |  Hermann-von-Helmholtz-Platz 1
fax:    (+49) 07247/82-2849     |  D-76344 Eggenstein-Leopoldshafen, Germany

--
Source code, list archive, and docs: http://www.mostang.com/sane/
To unsubscribe: echo unsubscribe sane-devel | mail majordomo@mostang.com