Category : C Source Code
Archive   : POPI.ZIP
Filename : SPECIAL.C

 
Output of file : SPECIAL.C contained in archive : POPI.ZIP

/* @(#)special.c 1.11 89/12/12
*
* Special transformations used by the popi program.
*
* Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
* This version is based on the code in his Prentice Hall book,
* "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
* which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
*
* Permission is given to distribute these extensions, as long as these
* introductory messages are not removed, and no monies are exchanged.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file) then an attempt will be made to fix them.
*/

/* Special transformations from chapter 6 of BP.
*
* The way this is done is fairly nasty at the moment,
* but it does work.
*/

#ifndef AMIGA
# include
#endif /* AMIGA */
#include
#include

#ifdef BSD
# include
#endif /* BSD */
#include "popi.h"

#define GAMMA 7.5 /* default gamma for matte() */
#define TILESIZE 25 /* default tile size for tile() */
#define N 3
#define New src[CURNEW].pix

/* prototypes for local functions */
struct SRC * parseimg P((void));
bool parsefname P((void));
void oil P((void));
void shear P((void));
void slice P((void));
void tile P((void));
void melt P((void));
void matte P((void));
void genps P((void));
void genepson P((void));
void list P((void));
void readimg P((void));
void writeimg P((void));
void freeimg P((void));
void displayimg P((void));
void CloseLog P((void));
void dolog P((void));
void debug P((void));
void undo P((void));
void verbose P((void));
void trunc P((void));

/*
* convenience function, since most of these routines have
* an image as their 1st parameter.
*/
static struct SRC *
parseimg()
{
lex();

if (lat == '\n' || lat == ')')
{
pushback(lat);
return &src[CUROLD];
}

if (lat != INAME)
{
SPRINTF(ErrBuf, "Expected image name");
error(ERR_PARSE);
return (struct SRC *) 0;
}

return &src[lexval + 1];
}

static bool
parsefname()
{
lex();

if (lat == '\n')
pushback(lat);

if (lat != FNAME)
{
SPRINTF(ErrBuf, "Expected file name");
error(ERR_PARSE);
return FALSE;
}
return TRUE;
}

static void
oil()
{
register int x, y;
register int dx, dy;
pixel_t mfp;
static int *histo = 0;
struct SRC *srcp;
pixel_t **img;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;
img = srcp->pix;

if
(
histo == (int *) 0
&&
(histo = (int *) LINT_CAST(Emalloc((unsigned)Zsize * sizeof (int)))) == (int *) 0
)
return;

if (disp_active)
disp_imgstart();

for (y = N; y < Ysize-N; y++)
{
for (x = N; x < Xsize-N; x++)
{
for (dx = 0; dx < Zsize; dx++)
histo[dx] = 0;
for (dy = y-N; dy <= y+N; dy++)
for (dx = x-N; dx <= x+N; dx++)
histo[img[dy][dx]]++;
for (dx = dy = 0; dx < Zsize; dx++)
if (histo[dx] > dy)
{
dy = histo[dx];
mfp = (pixel_t) dx;
}
New[y][x] = mfp;
}

if (disp_active)
disp_putline(New[y], y);
disp_percentdone(y * 100 / (Ysize-1));
}

if (disp_active)
disp_imgend();

SwapOldNew();
}


static void
shear()
{
register int x, y, r;
int dx, dy;
static int *yshift = 0;
struct SRC *srcp;
pixel_t **img;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;

img = srcp->pix;

if
(
yshift == 0
&&
(yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof(int)))) == 0
)
return;

if (disp_active)
disp_imgstart();

for (x = r = 0; x < Xsize; x++)
{
if (RANDOM % Zsize < 128)
r--;
else
r++;
yshift[x] = r;
}

for (y = 0; y < Ysize; y++)
{
if (RANDOM % Zsize < 128)
r--;
else
r++;

for (x = 0; x < Xsize; x++)
{
dx = x + r;
dy = y + yshift[x];
if (dx >= Xsize || dy >= Ysize || dx < 0 || dy < 0)
continue;
New[y][x] = img[dy][dx];
}

if (disp_active)
disp_putline(New[y], y);
disp_percentdone(y * 100 / (Ysize-1));
}

if (disp_active)
disp_imgend();

SwapOldNew();
}


static void
slice()
{
register int x, y, r;
int dx, dy;
struct SRC *srcp;
pixel_t **img;
static int *xshift = 0,
*yshift = 0;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;
img = srcp->pix;

if
(
xshift == 0
&&
(xshift = (int *) LINT_CAST(Emalloc((unsigned)Ysize * sizeof (int)))) == 0
)
return;
if
(
yshift == 0
&&
(yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof (int)))) == 0
)
return;

if (disp_active)
disp_imgstart();

for (x = dx = 0 ; x < Xsize; x++)
{
if (dx == 0)
{
r = (RANDOM & 63) - 32;
dx = 8 + RANDOM & 31;
}
else
dx--;
yshift[x] = r;
}
for (y = dy = 0; y < Ysize; y++)
{
if (dy == 0)
{
r = (RANDOM & 63) - 32;
dy = 8 + RANDOM & 31;
}
else
dy--;
xshift[y] = r;
}

for (y = 0; y < Ysize; y++)
{
for (x = 0; x < Xsize; x++)
{
dx = x + xshift[y];
dy = y + yshift[x];
if (dx < Xsize && dy < Ysize && dx >= 0 && dy >= 0)
New[y][x] = img[dy][dx];
}

if (disp_active)
disp_putline(New[y], y);
disp_percentdone(y * 100 / (Ysize-1));
}

if (disp_active)
disp_imgend();

SwapOldNew();
}


static void
tile()
{
register int x,
y,
dx,
dy;
int ox,
oy,
nx,
ny,
TileSize = TILESIZE;
struct SRC *srcp;
pixel_t **img;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;
img = srcp->pix;

for (y = 0; y < Ysize-TileSize; y += TileSize)
{
for (x = 0; x < Xsize-TileSize; x += TileSize)
{
ox = (RANDOM & 31) - 16 ; /* Displacement. */
oy = (RANDOM & 31) - 16;

for (dy = y; dy < y+TileSize; dy++)
for (dx = x; dx < x+TileSize; dx++)
{
nx = dx + ox;
ny = dy + oy;
if (nx >= Xsize || ny >= Ysize || nx < 0 || ny < 0)
continue;
New[ny][nx] = img[dy][dx];
}
}
disp_percentdone(y * 100 / (Ysize-1));
}

if (disp_active)
{
disp_imgstart();
for (y = 0; y < Ysize; y++)
disp_putline(New[y], y);
disp_imgend();
}

SwapOldNew();
}


/*
* Note: affects source image in situ.
* Buffers not swapped after processing.
*/
static void
melt()
{
register int x,
y,
k,
NumPixels;
pixel_t val;
struct SRC *srcp;
pixel_t **img;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;
img = srcp->pix;

NumPixels = Xsize * Ysize;
for (k = 0; k < NumPixels; k++)
{
x = RANDOM % Xsize;
y = RANDOM % (Ysize - 1);

while (y < Ysize-1 && img[y][x] <= img[y+1][x])
{
val = img[y][x];
img[y][x] = img[y+1][x];
img[y+1][x] = val;
y++;
}
disp_percentdone(k * 100 / (NumPixels-1));
}
if (disp_active)
{
disp_imgstart();
for (y = 0; y < Ysize; y++)
disp_putline(img[y], y);
disp_imgend();
}
}


static void
matte()
{
struct SRC *srcp;
pixel_t **img;
double gamma;
register x,
y;
static pixel_t *lookup = (pixel_t *) 0;
static double lastgamma = 0.0;

DEBUG((Debug, "matte()\n"));

if ((srcp = parseimg()) == (struct SRC *) 0)
return;
img = srcp->pix;

lex();
if (lat == '\n' || lat == ')')
{
gamma = GAMMA;
pushback(lat);
}
else
gamma = lexval + lexfract;

if
(
lookup == 0
&&
(lookup = (pixel_t *) Emalloc((unsigned)Zsize)) == (pixel_t *) 0
)
return;

if (lastgamma != gamma)
{
for (x = 0; x < Zsize; ++x)
lookup[x] = ((double)Zmax * pow(x / (double)Zmax, gamma) < 3.0)
? Zmax : 0;
lastgamma = gamma;
}

if (disp_active)
disp_imgstart();
for (y = 0; y < Ysize; y++)
{
for (x = 0; x < Xsize; x++)
New[y][x] = lookup[img[y][x]];
if (disp_active)
disp_putline(New[y], y);
disp_percentdone(y * 100 / (Ysize-1));
}
if (disp_active)
disp_imgend();
}

static void
genps()
{
int x,
y;
FILE *ostr;
struct SRC *srcp;
pixel_t **img,
*ip;
time_t time P((time_t *)),
clock;
#if unix
char *getlogin P((void));
#endif /* unix */

if (!parsefname())
return;

if ((ostr = EfopenW(text)) == NULL)
return;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;

img = srcp->pix;
clock = time((time_t *) 0);

FPRINTF(ostr, "%%!PS-Adobe-1.0\n");
FPRINTF(ostr, "%%%%Title: popi bit image '%s'\n", srcp->str);
FPRINTF(ostr, "%%%%DocumentFonts:\n");
FPRINTF(ostr, "%%%%Creator: popi\n");
FPRINTF(ostr, "%%%%CreationDate: %s", ctime(&clock)); /* includes \n */
FPRINTF(ostr, "%%%%Pages: 1\n");
#if unix
FPRINTF(ostr, "%%%%For: %s\n", getlogin());
#endif /* unix */
FPRINTF(ostr, "%%%%EndComments\n");
FPRINTF(ostr, "clippath pathbbox pop pop translate\n");
FPRINTF(ostr, "clippath pathbbox pop exch pop exch sub dup scale\n");
FPRINTF(ostr, "/picstr %d string def\n", Xsize);
FPRINTF(ostr, "/doimage {\n");
FPRINTF(ostr, "%d %d %d [ %d 0 0 -%d 0 %d ]\n",
Xsize, Ysize, BITSPERPIXEL, Xsize, Ysize, Ysize);
FPRINTF(ostr, "{currentfile picstr readhexstring pop}image}bind def\n");
FPRINTF(ostr, "%%%%EndProlog\n%%%%Page 0 0\ndoimage\n");

for(y = 0; y < Ysize; ++y)
{
ip = &img[y][0];
for(x = 0; x < Xsize; ++x)
{
if (x % 40 == 0) /* formatting only */
PUTC('\n', ostr);
FPRINTF(ostr, "%02x", *ip++);
}
PUTC('\n', ostr);
}

FPRINTF(ostr, "showpage\n");
Efclose(ostr);
}

/*
* Although this is set up to use one particular graphics mode
* of a 24-pin printer, everything should be generic enough
* that it can be changed to work with a different graphics
* mode on an 8-pin printer, just by changing a few numbers.
*/
static void
genepson()
{
struct SRC *srcp;
char *PinVals;
pixel_t *PinThresh,
ThreshStep;
FILE *ostr;
register int x;
register pixel_t **img;
int y,
yn;
int pin;
int BytesPerChunk,
PinsPerPixel,
BytesPerColumn,
yPixelsPerByte,
xPinsPerPixel,
yPinsPerPixel;

if (parsefname() == 0)
return;

if ((ostr = EfopenW(text)) == NULL)
return;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;

img = srcp->pix;

/* printer specific */
xPinsPerPixel = 4;
yPinsPerPixel = 4;
BytesPerColumn = 24 / BITSINBYTE;

PinsPerPixel = xPinsPerPixel * yPinsPerPixel;
BytesPerChunk = xPinsPerPixel * BytesPerColumn;
yPixelsPerByte = BITSINBYTE / yPinsPerPixel;

/* Must be whole number of pixels (y direction) per byte. */
assert(yPinsPerPixel * yPixelsPerByte == BITSINBYTE);

/* Reallocate these each time, as changing the print mode
* may change the sizes of these arrays.
*/
if
(
(PinVals = Emalloc((unsigned)BytesPerChunk)) == 0
||
(PinThresh = (pixel_t *) Emalloc((unsigned)PinsPerPixel * sizeof(pixel_t))) == 0
)
return;

ThreshStep = (pixel_t) (Zsize / (PinsPerPixel + 1));
for (pin = 0; pin < PinsPerPixel; ++pin)
PinThresh[pin] = (pixel_t) ((pin + 1) * ThreshStep);

for (y = 0; y < Ysize; y = yn)
{

/* printer specific */
/*
* This print line is width Xsize pixels, and (Xsize * xPinsPerPixel)
* pin positions (dots on the page).
* No. of dots vertical is (BytesPerColumn * BITSINBYTE)
* which is yPinsPerPixel times the no. of image scanlines.
*/
FPRINTF(ostr,
"\033*%c%c%c",
39, /* 180 dpi in both directions */
(Xsize * xPinsPerPixel) % 256,
(Xsize * xPinsPerPixel) / 256
);

for (x = 0; x < Xsize; ++x)
{
register int ycur;
int ByteCount,
xpin;
char *dp;

/* Clear the PinVals array */
for
(
ByteCount = 0, dp = PinVals;
ByteCount < BytesPerChunk;
++ByteCount
)
*dp++ = 0;

dp = PinVals;

/* For each byte-sized row of the print head,
* collect 1 pixel width of data.
*/
for
(
ByteCount = 0, dp = PinVals, ycur = y;
ByteCount < BytesPerColumn;
++ByteCount, dp += xPinsPerPixel
)
{
register unsigned char bit;

yn = ycur + yPixelsPerByte;
if (yn > Ysize)
yn = Ysize;

/* For the current byte row of the print-head
* (ie yPixelsPerByte image scanlines),
* collect a pixel width of data.
*/
for (bit = 0x80; ycur < yn; ++ycur)
{
pixel_t val;
int ypin;

val = img[ycur][x];

/* Now use an appropriate no. of pins to simulate
* the greyscale value.
*/
for
(
ypin = 0, pin = 0;
ypin < yPinsPerPixel;
++ypin
)
{
for (xpin = 0; xpin < xPinsPerPixel; ++xpin, ++pin)
{
if (val < PinThresh[pin])
dp[xpin] |= bit;
}
/* xpin == xPinsPerPixel */
bit >>= 1;
}
/* ypin == YpinsPerPixel */
}
/* ycur == y */
}
/* ByteCount == BytesPerColumn */

/* We have set up enough columns for a single pixel in
* the x direction. Now print them in the correct order.
*/
for (xpin = 0; xpin < xPinsPerPixel; ++xpin)
{
for (ByteCount = 0; ByteCount < BytesPerColumn; ++ByteCount)
{
PUTC(PinVals[ByteCount * xPinsPerPixel + xpin], ostr);
}
}
/* xpin == xPinsPerPixel */
}
/* x == Xsize */

/* Printer specific */
FPRINTF(ostr, "\033J%c\r", 24);
}
/* y == Ysize */

Efclose(ostr);
free(PinVals);
free((char *) PinThresh);
}

static void
list()
{
showfiles();
}

/*
* #read "filename" [imagename]
*/
static void
readimg()
{
char filename[512],
*imgname = (char *) 0;

if (parsefname() == 0)
return;

STRCPY(filename, text);

lex();

if (lat == '\n' || lat == ')')
{
pushback(lat);
}
else if (lat != NAME && lat != INAME)
{
SPRINTF(ErrBuf, "Expected image name");
error(ERR_PARSE);
}
else
imgname = text;

getpix(filename, imgname);
}

static void
writeimg()
{
struct SRC *srcp;

if (parsefname() == 0)
return;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;

putpix(srcp, text);
}

static void
freeimg()
{
struct SRC *srcp;

if ((srcp = parseimg()) == (struct SRC *) 0)
return;

if (srcp == &src[CUROLD] || srcp == &src[CURNEW])
{
SPRINTF(ErrBuf, "Cannot free 'old' or 'new'");
error(0);
return;
}

ImgFree(srcp);
}

static void
displayimg()
{
pixel_t **img;
int y;


lex();

if (lat == '+')
{
disp_active = 1;
return;
}
if (lat == '-')
{
disp_active = 0;
return;
}
if (lat == '\n')
{
pushback(lat);
img = src[CUROLD].pix;
}
else if (lat == INAME)
img = src[lexval + 1].pix;
else if (lat == NEW)
img = src[CURNEW].pix;
else
{
SPRINTF(ErrBuf, "Expected +, - or image name");
error(ERR_PARSE);
return;
}

disp_imgstart();

for (y = 0; y < Ysize; y++)
disp_putline(img[y], y);

disp_imgend();
}

static void
CloseLog()
{
if (LogStr == NULL)
return;

FPRINTF(LogStr, "\n---\n");
FCLOSE(LogStr);
LogStr = NULL;
}

void
OpenLog()
{
time_t time(),
clock;

CloseLog();

if ((LogStr = fopen(LogFile, "a")) == NULL)
{
SPRINTF(ErrBuf,
"Can't open log file '%s' - logging is off",
LogFile);
error(ERR_SYS);
return;
}

clock = time((time_t *) 0);
FPRINTF(LogStr, "==>> %s", ctime(&clock)); /* includes '\n' */
}

static void
dolog()
{
static char *buf = (char *) 0;

lex();

if (lat == '+')
OpenLog();
else if (lat == '-')
CloseLog();
else if (lat == FNAME)
{
if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
return;
STRCPY(buf, text);
LogFile = buf;
OpenLog();
}
else
pushback(lat);

if (LogStr)
PRINTF("Logging is active on file '%s'\n", LogFile);
else
PRINTF("Logging is off\n");
}

static void
debug()
{
static char *buf = (char *) 0;

lex();

if (lat == '+')
OpenLog();
else if (lat == '-')
CloseLog();
else if (lat == FNAME)
{
if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
return;
STRCPY(buf, text);
LogFile = buf;
OpenLog();
}
else
pushback(lat);

if (LogStr)
PRINTF("Logging is active on file '%s'\n", LogFile);
else
PRINTF("Logging is off\n");
}

static char *HelpMsg[] =
{
"binary ops: ** * / % + - << >> < > >= <= == != & ^ | && ||",
"funcs: sin(deg) cos(deg) atan(y, x) log(val) sqrt(val) abs(val) rand()",
"values: x y r a X Y R A Z",
"special funcs",
"\t#read \"filename\"",
"\t#write \"filename\"",
"\t#genps \"filename\" [image]",
"\t#display [image]",
"\t#display +",
"\t#display -",
(char *) 0
};

void
help()
{
PrStrs(HelpMsg);
}

static void
undo()
{
SwapOldNew();
}

static void
verbose()
{
lex();

if (lat == '+')
Verbose = 1;
else if (lat == '-')
Verbose = 0;
else
pushback(lat);

PRINTF("Verbose is %s\n", Verbose ? "on" : "off");
}

static void
trunc()
{
lex();

if (lat == '+')
Truncate = 1;
else if (lat == '-')
Truncate = 0;
else
pushback(lat);

PRINTF("Truncation is %s\n", Truncate ? "on" : "off");
}

struct SpecialOp
{
char *name;
void (*func) P((void));
};

static struct SpecialOp SpecialOps[] =
{
{ "matte", matte },
{ "oil", oil },
{ "slice", slice },
{ "shear", shear },
{ "tile", tile },
{ "melt", melt },
{ "read", readimg },
{ "write", writeimg },
{ "genps", genps },
{ "genepson", genepson },
{ "list", list },
{ "display", displayimg },
{ "debug", debug },
{ "version", version },
{ "verbose", verbose },
{ "truncate", trunc },
{ "undo", undo },
{ "help", help },
{ "free", freeimg },
{ "logfile", dolog },
{ (char *) 0, (void (*) P((void)) ) 0 }
};

void
special()
{
struct SpecialOp *sp;

DEBUG((Debug, "special\n"));
lex();
if (! (lat == NAME || isalpha(lat)))
{
SPRINTF(ErrBuf, "Expected name of special operation");
error(ERR_PARSE);
return;
}

sp = SpecialOps;
for (sp = SpecialOps; sp->name && strcmp(text, sp->name) != 0; ++sp)
;

if (! sp->name)
{
SPRINTF(ErrBuf,
"Special operation '%s' unrecognised",
text);
error(ERR_PARSE);
return;
}

DEBUG((Debug, "calling func '%s'\n", sp->name));
(*(sp->func))();

if (lat != '\n')
lex();

if (lat != '\n')
{
SPRINTF(ErrBuf, "Tokens after special command ignored");
error(ERR_WARN);
}

assert(lat == '\n');
}


  3 Responses to “Category : C Source Code
Archive   : POPI.ZIP
Filename : SPECIAL.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/