home *** CD-ROM | disk | FTP | other *** search
- From: richb@sunaus.sun.oz.AU (Rich Burridge)
- Newsgroups: comp.sources.misc
- Subject: v09i050: popi, The Digital Darkroom, Part04/09
- Message-ID: <2784@basser.oz>
- Date: 12 Dec 89 23:46:51 GMT
- Approved: john@cs.su.oz.AU (John Mackin - comp.sources.misc)
-
- Posting-number: Volume 9, Issue 50
- Submitted-by: Rich Burridge <richb@sunaus.sun.oz.AU>
- Archive-name: popi/part04
-
- ---- Cut Here and unpack ----
- #!/bin/sh
- # this is part 4 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file run.c continued
- #
- CurArch=4
- if test ! -r s2_seq_.tmp
- then echo "Please unpack part 1 first!"
- exit 1; fi
- ( read Scheck
- if test "$Scheck" != $CurArch
- then echo "Please unpack part $Scheck next!"
- exit 1;
- else exit 0; fi
- ) < s2_seq_.tmp || exit 1
- echo "x - Continuing file run.c"
- sed 's/^X//' << 'Funky_Stuff' >> run.c
- X ++rp;
- X }
- X
- X#if SEQPAR
- X if (m_myid == 0)
- X#endif /* SEQPAR */
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X
- X#if 0
- X if (nrange != 0)
- X FPRINTF(stderr,
- X "Total of %d range errors corrected\n",
- X nrange);
- X#endif
- X}
- X
- Xvoid
- Xrun()
- X{
- X int y;
- X#if SEQPAR
- X static int parked = 0;
- X
- X if (parked)
- X m_rele_procs();
- X m_fork(prun);
- X m_kill_procs(); /* For some reason, parking doesn't work properly ...
- X m_park_procs();
- X parked = 1; /* so it can be released above */
- X#else /* ! SEQPAR */
- X prun();
- X#endif /* ! SEQPAR */
- X
- X disp_percentdone(100); /* Can rely on '100' to terminate */
- X
- X if (disp_active)
- X {
- X disp_imgstart();
- X for (y = 0; y < Ysize; ++y)
- X disp_putline(src[CURNEW].pix[y], y);
- X disp_imgend();
- X }
- X
- X SwapOldNew();
- X}
- Funky_Stuff
- echo "File run.c is complete"
- chmod 0444 run.c || echo "restore of run.c fails"
- set `wc -c run.c`;Sum=$1
- if test "$Sum" != "8692"
- then echo original size 8692, current size $Sum;fi
- echo "x - extracting popi.prj (Text)"
- sed 's/^X//' << 'Funky_Stuff' > popi.prj &&
- X
- X
- XEXPR
- XIBMPC
- XIO
- XLEX
- XMAIN
- XPOLAR
- XRUN
- XSPECIAL
- Xgraphics.lib
- Funky_Stuff
- chmod 0444 popi.prj || echo "restore of popi.prj fails"
- set `wc -c popi.prj`;Sum=$1
- if test "$Sum" != "56"
- then echo original size 56, current size $Sum;fi
- echo "x - extracting powerc.prj (Text)"
- sed 's/^X//' << 'Funky_Stuff' > powerc.prj &&
- X# Project file for Mix Software's Power C Compiler
- X# Compile with "pc powerc.prj"
- Xmain popi.h main.c
- Xexpr popi.h expr.c
- Xio popi.h io.c
- Xlex popi.h lex.c
- Xpolar popi.h polar.c
- Xrun popi.h run.c
- Xspecial popi.h special.c
- Xibmpc popi.h ibmpc.c
- Xpopi.exe main expr io lex polar run special ibmpc
- Funky_Stuff
- chmod 0444 powerc.prj || echo "restore of powerc.prj fails"
- set `wc -c powerc.prj`;Sum=$1
- if test "$Sum" != "286"
- then echo original size 286, current size $Sum;fi
- echo "x - extracting popi.1 (Text)"
- sed 's/^X//' << 'Funky_Stuff' > popi.1 &&
- X.\" @(#)popi.1 1.8 89/12/11
- X.\"OPTIONS man
- X.TH POPI 1L "12 December 1989"
- X.tr @"
- X.\"These macros always explicitly return to font 1, rather than the
- X.\"previous font, because previous may have been altered.
- X.de C
- X.\" Start constant width
- X.sp 0.5
- X.nf
- X.po +2c
- X.ft CW
- X..
- X.\" End constant width
- X.de E
- X.sp 0.5
- X.po
- X.ft 1
- X.fi
- X..
- X.de CW
- X\&\f(CW\\$1\&\f1\\$2\&
- X..
- X.ie t .ds Mu \(mu
- X.el .ds Mu x
- X.ie t .ds +- \(+-
- X.el .ds +- +-
- X.\"-------------------------------------------------------------------------
- X.SH NAME
- Xpopi \- perform interactive digital image transformations
- X.SH SYNOPSIS
- X.B "popi [option] ... [file] ..."
- X.SH DESCRIPTION
- X.I Popi
- Xis a program which allows arbitrary transformations to be
- Xinteractively applied to digital images.
- XIt is based on the program described in "Beyond Photography
- X\- The Digital Darkroom" by Gerald J. Holzmann.
- X.P
- XThe meanings of the available command line options are as follows:
- X.TP
- X.BI \-V
- XPrint program version identification message and exit.
- X.TP
- X.BI \-x Width
- XSet the image width (number of pixels per scanline) to
- X.I Width .
- X.TP
- X.BI \-y Height
- XSet the image height (number of scanlines) to
- X.I Height .
- X.TP
- X.BI \-v+
- XSet the verbose flag on.
- XBe chatty about a number of things.
- X.TP
- X.BI \-v\-
- XTurn the verbose flag off.
- XBe silent about everything except error messages.
- X.TP
- X.BI \-a+
- XTurn auto-display on.
- XAfter each image transformation, the image will be displayed.
- XEquivalent to the
- X.CW "#display +"
- Xcommand.
- X.TP
- X.BI \-a\-
- XTurn auto-display off.
- XEquivalent to the
- X.CW "#display \-"
- Xcommand.
- XImages can still be displayed explicitly with the
- X.CW "#display \f2image\fP"
- Xcommand.
- X.TP
- X.BI \-p [ncpus]
- XOn a Sequent multiprocessor, use the specified number of cpus
- Xto perform the transform.
- XIf this option is given without a number, the maximum number
- Xavailable is used.
- XThis option has no effect on uniprocessor computers.
- X.TP
- X.BI \-l [logfile]
- XEnables logging of all input, error messages, and some
- Xresponses.
- XLogging is done on the named file, or the file "popi.log" if no
- Xname is given.
- XThe
- X.CW "#logfile"
- Xcommand may also be used to turn logging on and off.
- X.P
- XAn image transform is described by a transform statement.
- XThe statement basically takes the form
- X.C
- X\f2dest\fP = \f2expression\fP
- X.E
- Xwhere
- X.I dest
- Xindicates the new image and
- X.I expression
- Xdescribes a transformation.
- XThis statement is executed over the range of image
- Xcoordinates.
- XFor a 512 \*(Mu 512 image, it will be executed 262144 times.
- XAn image is normally referenced in a statement by its name
- Xand an index.
- XA cartesian index is specified by using the x and y
- Xcoordinates in square brackets after the image name.
- XThus
- X.CW dmr[0,0]
- Xis the top left pixel in the image named
- X.CW dmr .
- XPolar coordinates may be specified by giving a radius and
- Xangle (in degrees) in curly brackets.
- XThus
- X.CW dmr{0,0}
- Xrefers to the centre pixel in the
- Ximage.
- XThe symbols
- X.CW x
- Xand
- X.CW y
- Xmay appear in the transform statement.
- XThese take on values corresponding to a different pixel each
- Xtime the transform is executed.
- XInternally the algorithm is as follows
- X.sp 0.5
- X.nf
- Xfor y varying from 0 to Y
- X for x varying from 0 to X
- X execute transform statement
- X.sp 0.5
- X.fi
- Xwhere
- X.CW Y
- Xis the maximum y coordinate and
- X.CW X
- Xis the maximum x coordinate.
- XThe image size can be set on the command line as described
- Xlater.
- X.P
- XThe value of a pixel varies from 0 to 255 in the current
- Ximplementation.
- XAny value outside this range is treated as modulo 256 when
- Xbeing stored in an image (ie. it wraps around).
- XLow numeric values represent dark colours, while large values
- Xrepresent light colours.
- XA simple transform statement to set an image to completely
- Xblack would be
- X.C
- Xnew[x,y] = 0 ; set image to black
- X.E
- XThe name
- X.CW new
- Xis one of the two default images always maintained internally.
- XThe other is
- X.CW old .
- XThe images referred to by these names are swapped after each
- Xoperation, so a succession of transforms may modify the "old"
- Ximage to produce a "new" image.
- XThus the statement
- X.C
- Xnew[x,y] = old[x,y] / 2 ; darken image
- X.E
- Xwill reduce all the pixel intensity values by a half,
- Xdarkening the existing image.
- XThe semicolon (`;') character introduces a comment.
- XAnything from this to the end of the line is ignored.
- X.P
- XAll the standard arithmetic, relational and boolean operators
- Xfrom the C language are available, with precedence generally
- Xas per the C language.
- XSome additional operators, predefined variables and math
- Xfunctions are also available.
- X.P
- XHere is a listing of the available symbols and their
- Xmeanings.
- X.TP
- X\f2name\fP
- XRefers to an image name.
- XIf not followed by index brackets, the index
- X.CW "[x,y]"
- Xis assumed.
- XThe currently available names are those shown by the
- X.CW #list
- Xdisplay, and also
- X.CW old
- Xand
- X.CW new .
- X.TP
- X.CW $\f2n\fP
- XWhere \f2n\fP is a digit, this is an alternative method of
- Xreferring to an image.
- XIn fact this may be the only method if the image name contains
- Xpunctuation characters.
- XThe
- X.CW #list
- Xcommand shows the correspondence between image names and this
- Xform of reference.
- X.TP
- X.CW X
- XThe maximum x coordinate value.
- XThis is one less than the number of pixels per scanline
- X(image width), which may be set with the
- X.B \-x
- Xcommand line option.
- X.TP
- X.CW Y
- XThe maximum y coordinate value.
- XThis is one less than the number of scanlines (the height of
- Xthe image), which may be set with the
- X.B \-y
- Xcommand line option.
- X.TP
- X.CW x
- XThe current cartesian x coordinate.
- XVaries from 0 (left of image) to
- X.CW X
- X(right of image).
- X.TP
- X.CW y
- XThe current cartesian y coordinate.
- XVaries from 0 (top of image) to
- X.CW Y
- X(bottom of image).
- X.TP
- X.CW r
- XThe radius component of the polar coordinate which corresponds to the
- Xcurrent cartesian (x,y) coordinate.
- XThis is equivalent to
- X.CW "sqrt(x*x + y*y)"
- Xwith a translation of the origin.
- X.TP
- X.CW a
- XThe angle component of the polar coordinate which corresponds to the
- Xcurrent cartesian (x,y) coordinate.
- XThis is equivalent to (and a shorthand for)
- X.CW "atan(y/x)" .
- X.sp
- XNote that the first time in a popi session you use an expression with either
- X.CW r
- Xor
- X.CW a
- Xin it, you may notice an extra delay before the image
- Xtransformation begins.
- XThis is due to precalculation of an array of polar coordinates
- Xthat happens the first time you use one.
- X.TP
- X.CW R
- XThe maximum radius value of a polar coordinate.
- X.TP
- X.CW A
- XThe maximum angle value of a polar coordinate (this is just 360).
- X.TP
- X.CW Z
- XThe maximum intensity value of a pixel (corresponding to white).
- XCurrently, this is always 255.
- X.TP
- X.CW **
- XThe exponentiation (raise to the power) operator.
- XThe expression
- X.CW "x ** 2"
- Xmeans x squared (x * x).
- X.TP
- X.CW *
- XThe multiplication operator.
- XThis has a higher precedence than division to avoid underflow
- Xin expressions with multiplication and division, since normally
- Xexpressions are evaluated as integers.
- X.TP
- X.CW /
- XInteger division.
- XIf the divisor is 0, the result is set to Z.
- X.TP
- X.CW %
- XModulo.
- XIf the divisor (right hand operand) is 0, the result is set to 0.
- X.TP
- X.CW "+"
- XAddition.
- X.TP
- X.CW "\-"
- XSubtraction.
- XThis may be a unary or a binary operator.
- X.TP
- X.CW "<<"
- XLeft shift.
- XThe left operand is shifted left the number of bits specified by the
- Xright operand.
- X.TP
- X.CW ">>"
- XRight shift.
- XThe left operand is shifted right the number of bits specified by the
- Xright operand.
- X.TP
- X.CW ">"
- XGreater than.
- XAs with all the relational operators, if the specified relation between
- Xthe operands is true, the result is 1, otherwise the result is 0.
- X.TP
- X.CW "<"
- XLess than.
- X.TP
- X.CW ">="
- XGreater than or equal to.
- X.TP
- X.CW "<="
- XLess than or equal to.
- X.TP
- X.CW "=="
- XTest for equality.
- X.TP
- X.CW "!="
- XNot equal to.
- X.TP
- X.CW "&"
- XBitwise (arithmetic) AND operator.
- X.TP
- X.CW "^"
- XBitwise exclusive OR (XOR) operator.
- X.TP
- X.CW "|"
- XBitwise (arithmetic) OR operator.
- X.TP
- X.CW "&&"
- XLogical AND operator.
- XThe result is 1 if both of the operands are true (non-zero);
- Xotherwise the result is 0.
- XUnlike the && operator of the C language, this operator is currently not
- Xconditional.
- XBoth operands are always evaluated.
- X.TP
- X.CW "||"
- XLogical OR operator.
- XThe result is 1 if both either (or both) of the operands are true
- X(non-zero); otherwise the result is 0.
- XUnlike the || operator of the C language, this operator is currently not
- Xconditional.
- XBoth operands are always evaluated.
- X.TP
- X.CW sin(\f2expr\fP)
- XThis gives the value of the trigonometric sine of the expression,
- Xmultiplied by Z.
- XThis is required because all operations are performed with integers.
- X.TP
- X.CW cos(\f2expr\fP)
- XThis gives the value of the trigonometric cosine of the expression,
- Xmultiplied by Z.
- XThis is required because all operations are performed with integers.
- X.TP
- X.CW atan(\f2y-expr\fP,\f2x-expr\fP)
- XThis returns the trigonometric arctangent (inverse tangent) of
- X.I y-expr/x-expr
- Xin degrees (ie the value returned will be between 0 and 360).
- X.TP
- X.CW log(\f2expr\fP)
- XReturns the natural logarithm of the expression.
- X.TP
- X.CW sqrt(\f2expr\fP)
- XReturns the square root of the expression.
- X.TP
- X.CW rand()
- XReturns a positive random number.
- XThis will usually be used with the modulo or bitwise AND
- Xoperator to restrict the range of the result.
- XFor example,
- X.C
- Xnew[x,y] = old[x,y] + rand() % 20 \- 10
- X.E
- Xwill adjust the brightness levels of each pixel in the old image by a
- Xrandom amount (up to 10 levels brighter or darker).
- X.\".TP
- X.\".CW rand(\f2expr\fP)
- X.\"Returns a positive random number between 0 and the value of
- X.\"the parameter.
- X.\"This is provided as a more efficient alternative to
- X.\".CW "rand() % \f2expr\fP"
- X.\"The previous example could thus be rewritten as:
- X.\".C
- X.\"new[x,y] = old[x,y] + rand(20) \- 10
- X.\".E
- X.P
- XAs well as allowing transformation statements, a number of special
- Xcommands, each starting with a
- X.CW #
- Xcharacter, are allowed.
- XThese are described here.
- X.TP
- X.CW "#read @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
- XRead a raw data file into the named image.
- XIf no image name is specified, the name is derived from the base name
- Xcomponent of the filename.
- XIf the name already exists, that image is overwritten in memory,
- Xotherwise a new image is created.
- XIf the filename does not exist, but the same name with a ".Z"
- Xsuffix does exist, it is assumed that the file is compressed
- Xand the "zcat" program is used to read the compressed image.
- XNote that when the image name defaults to the file name, only
- Xthe basename (portion after the last '/' character, if any) is
- Xused to name the image.
- XIf this resulting name starts with a digit, or contains any
- Xcharacters other than alphabetic, digits and the underscore,
- Xyou will not be able to reference the image by name, but will
- Xhave to use the alternative "$n" syntax.
- X.TP
- X.CW "#write @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
- XWrite a raw data file from the named image.
- XThe image name is optional, and
- Xif not specified, image "old" is used.
- XIf the first character of the filename is `|', the rest of the filename
- Xis interpreted as a command to be run, with the raw image data being fed
- Xto it as standard input.
- X.TP
- X.CW "#list"
- XAll the named images (other than "old" and "new" are listed).
- X.TP
- X.CW "#genps @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
- XGenerate postscript to produce the image.
- XThe image name is optional, and
- Xif not specified, image "old" is used.
- XThe image will be scaled to fit whatever paper size is being used.
- XAs with the
- X.CW #write
- Xcommand, if the first character of the filename is a `|' symbol, the
- Xrest of the string will be treated as a command to be executed, with the
- Xpostscript being piped to its standard input.
- XThis is convenient for printing images on a PostScript printer.
- X.TP
- X.CW #undo
- XThe
- X.CW old
- Xand
- X.CW new
- Ximages are swapped.
- XThis has the effect of restoring the image that existed
- Xbefore the last transformation.
- X.TP
- X.CW "#genepson @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
- XGenerate data for an Epson (or compatible) printer to produce
- Xthe image.
- XThe image name is optional, and if not specified, image "old" is used.
- XUnder MSDOS, the device name can be used directly (eg "PRN").
- X.sp
- XThe existing code is for a 24-pin printer such as the LQ-500.
- XTo generate data for an 8-pin printer requires a couple of
- Xminor modifications to function
- X.CW genepson()
- Xin file
- X.CW special.c .
- X.TP
- X.CW #undo
- XThe
- X.CW old
- Xand
- X.CW new
- Ximages are swapped.
- XThis has the effect of restoring the image that existed
- Xbefore the last transformation.
- X.TP
- X.CW "#display \f2image-name\fP"
- XThe named image will be displayed.
- XThis is the fastest way to display an image, and works regardless of the
- Xstate of auto-display.
- X.TP
- X.CW "#display +"
- XTurn auto-display on (equivalent to the command-line option
- X.B \-a+ ).
- X.TP
- X.CW "#display \-"
- XTurn auto-display off (equivalent to the command-line option
- X.B \-a\- ).
- X.TP
- X.CW "#truncate +"
- XAll assignments to an image with values outside the range
- X.CW 0
- Xto
- X.CW Z
- Xwill be truncated to the appropriate boundary, instead of
- Xwrapping as described in the book.
- XAn example of using this feature would be for a simplistic
- Xlightening of an image by adding a constant value.
- XNormally, very white areas would wrap around and become black,
- Xbut enabling truncation prevents this.
- X.TP
- X.CW "#truncate \-"
- XAll assignments to an image will be done modulo
- X.CW "(Z+1)" .
- XThis is the default.
- X.TP
- X.CW "#verbose +"
- XTurn on verbose mode.
- XEquivalent to the
- X.CW "\-v+" command line option.
- XCertain warning messages will be printed.
- XThis turns on the "percent done" feature of some drivers (on
- Xothers it is always active).
- X.TP
- X.CW "#truncate"
- XReport whether truncation is currently in effect or not.
- X.TP
- X.CW "#verbose \-"
- XTurn off verbose mode.
- XEquivalent to the
- X.CW "\-v\-" command line option.
- X.TP
- X.CW "#verbose"
- XReport the state of the verbose flag.
- X.TP
- X.CW "#logfile +"
- XEnable logging on the current log file (default "popi.log").
- XIf logging is already enabled, the file is closed and re-opened
- Xwith a new timestamp appended.
- X.TP
- X.CW "#logfile \-"
- XDisable logging"
- X.TP
- X.CW "#logfile @\f2filename\fP@"
- XEnable logging on the specified file.
- X.sp
- XWhenever a log file is opened, it is always opened in append
- Xmode, so existing data is never truncated.
- XUpon opening a log file, a timestamp is written.
- XAll user input is logged, along with error messages and some
- Xprogram responses.
- X.TP
- X.CW "#free \f2imagename\fP"
- XThe memory associated with the named image is freed.
- XAny further access to this image becomes impossible.
- XThis command may be useful in situations where memory is very
- Xlimited, such as a PC.
- X.P
- XThe remaining special commands are used to obtain special built-in
- Xtransformations, as described in Chapter 6 of "Beyond Photography".
- XIn each of these cases, the image name is optional, and defaults to
- X"old".
- XIn each case (except for
- X.CW #melt ),
- Xthe result is stored in "new", and then "old" and "new" are swapped as
- Xusual.
- XIn the case of
- X.CW #melt ,
- Xthe transformation is done in place and no swap occurs.
- X.TP
- X.CW "#oil \f2image-name\fP"
- X.TP
- X.CW "#shear \f2image-name\fP"
- X.TP
- X.CW "#slice \f2image-name\fP"
- X.TP
- X.CW "#tile \f2image-name\fP"
- X.TP
- X.CW "#melt \f2image-name\fP"
- X.TP
- X.CW "#matte \f2image-name\fP \f2gamma\fP"
- XIn this case,
- X.I gamma
- Xis an optional floating point number (defaults to 7.5).
- XSee the book for details.
- X.SH DIFFERENCES
- XThere are a number of differences between the Pico interpreter, for
- Xwhich the examples in the book are written, and the Popi interpreter as
- Ximplemented here.
- X.P
- XInteger evaluation stack.
- XThe current version of the interpreter has an integer evaluation stack.
- XFor this reason, the
- X.CW sin()
- Xand
- X.CW cos()
- Xfunctions, have their results multiplied by Z automatically in order to
- Xbe significant.
- XA future version of the interpreter will provide the option for a
- Xfloating point stack, and a syntax which will handle both cases.
- X.P
- XPolar coordinates.
- XIn the book, both cartesian and polar coordinates are specified with
- Xsquare brackets.
- XThe decision of whether to interpret the indices as polar or cartesian
- Xis based on context;
- Xif the symbols
- X.CW r
- Xand
- X.CW a
- Xare used in the index expressions, the coordinates are interpreted as
- Xpolar, otherwise they are interpreted as rectangular.
- XThus, in order to use a radius or angle in a cartesian coordinate
- Xexpression, it must be cast, as is done on page 48 of the book.
- XBy providing a separate syntax for polar and cartesian coordinate
- Xreferences, the problem never occurs.
- X.SH EXAMPLES
- XThese examples are mainly taken from the book, with syntax modifications
- Xwhere required.
- XThe images in the book are usually 1000 \*(Mu 1000 pixels.
- XTo produce the same results on a smaller image, you may need to multiply
- Xany occurences of
- X.CW x ,
- X.CW y
- Xand
- X.CW r
- Xby an appropriate scaling factor.
- XThe first example image generation in the book is
- X.C
- Xnew[x,y] = x + y ; page 17 (3.1)
- X.E
- Xwhich produces a number of diagonal stripes, each fading from black to
- Xwhite.
- XOn a 512 \*(Mu 512 image, to get the same number of stripes, use the
- Xtransform
- X.C
- Xnew[x,y] = x*2 + y*2
- X.E
- XA series of ripples can be produced with
- X.C
- Xnew[x,y] = (x * y) % (Z + 1) ; page 18 (3.2)
- X.E
- Xor more simply, because all brightness values are inherently modulo
- X.CW "(Z + 1)"
- Xunless truncation is turned on
- X.C
- Xnew[x,y] = x * y
- X.E
- XA single smooth transition can be accomplished with
- X.C
- Xnew[x,y] = (Z * x * y) / ((X\-1) * (Y\-1)) ; page 18 (3.3)
- X.E
- XThe transformation
- X.C
- Xnew[x,y] = x % y
- X.E
- Xis the same as
- X.CW "new[x,y] = x"
- Xwhen
- X.CW "x < 0"
- X(ie in the lower left triangle of the image, with a different effect in
- Xthe upper right half.
- X.P
- XThe trig functions allow transforms such as
- X.C
- Xnew[x,y] = y + sin(x) / 2 ; page 19 (3.5)
- X.E
- Xwhich produce a series of sine waves (remember that the range of
- X.CW "sin(x)"
- Xis
- X.CW "\*(+-Z" .
- X.P
- XAn image reminiscent of a radar sweep can be produced by
- X.C
- Xnew[x,y] = atan(y \- Y/2, x \- X/2) * Z / 360 ; page 19 (3.6)
- X.E
- XThe
- X.CW atan()
- Xfunction has a range of 0 .. 360, so the
- X.CW "*Z/360"
- Xrescales to 0 ..
- X.CW Z .
- XThis transform is overall providing an intensity relative to the angle
- Xof a point in polar coordinates.
- XThe transform language provides the current angle as the variable
- X.CW a ,
- Xso this statement can be rewritten as
- X.C
- Xnew[x,y] = a * Z / 360
- X.E
- XPolar coordinates can be used to produce an image which varies from
- Xblack in the centre to white on the outside
- X.C
- Xnew[x,y] = r * Z / R ; page 21 (3.11)
- X.E
- Xor a spiraling effect
- X.C
- Xnew[x,y] = (((a + r) % 16) \- 8) * Z / 16 + Z/2 ; page 21 (3.12)
- X.E
- XThe conditional operator can be used to provide a filled black circle
- X.C
- Xnew[x,y] = r > R/2 ? 0 : Z
- X.E
- Xor black and white patterns such as
- X.C
- Xnew[x,y] = ((x % (5 + y/25)) > 5) ? 0 : Z ; page 20 (3.9)
- Xnew[x,y] = (Z * abs(x % sin(y)) > 10) ? 0 : Z ; page 20 (3.10)
- X.E
- X.P
- XWe can also modify existing images using these transforms.
- XThe previous image can always be referred to as
- X.CW old ,
- Xor an explicitly named image can be used.
- XWe can read an image (eg of Dennis Ritchie) using
- X.C
- X#read "dmr" ; read the image in the file "dmr" and name it dmr.
- X.E
- Xand then use it in a transform, such as
- X.C
- Xnew[x,y] = Z \- dmr[x,y] ; page 22 (3.13)
- X.E
- XThis produces a negative, which can be written to a file with
- X.C
- X#write "dmr_neg"
- X.E
- Xor converted to PostScript and printed with
- X.C
- X#genps "| lp \-dalw"
- X.E
- XSince the
- X.CW new
- Ximage built during a transformation becomes the
- X.CW old
- Ximage of the following transform,
- Xthe negative image can be re-reversed to produce the original with
- X.C
- Xnew[x,y] = Z \- old[x,y] ; reverse the process
- X.E
- XIn the following examples, we will use
- X.CW old
- Xin most of the transforms, rather than a particular image name.
- XIn practice, you would probably use a specifically named image instead.
- X.P
- XProvide a circular frame for an image
- X.C
- Xnew[x,y] = r > R/2 ? 0 : old[x,y]
- X.E
- XA solarisation process, that fades in from left to right
- X.C
- Xnew[x,y] = (old[x,y] > (Z*x) / (2 * X)) ? old[x,y] : Z\-old[x,y] ; page 22 (3.16)
- X.E
- XGenerate a relief map
- X.C
- Xnew[x,y] = old[x,y] + (Z/2 \- old[x+2,y+2]) ; page 24 (3.19)
- X.E
- XShrink an image
- X.C
- Xnew[x,y] = old[x*2,y*2] ; page 25 (3.24)
- X.E
- X.P
- XAn interesting caricature is produced by
- X.C
- Xnew[x,y] = old{sqrt(r * R),a} ; page 34
- X.E
- XNote the use of polar coordinates.
- XThe reverse transform gives a fisheye lens effect:
- X.C
- Xnew[x,y] = old{(r*r)/R, a} ; page 60
- X.E
- XThe following transform illustrates how an expression can be used for
- Xthe indices of the destination matrix.
- X.C
- Xnew[x, y\-old[x,y]/4] = old[x,y] ; page 40
- X.E
- XAn image can be swirled about the centre with
- X.C
- Xnew[x,y] = old{r, a + r/3}
- X.E
- XThe following transform uses polar coordinate values in a cartesian
- Xreference, resulting in something that looks like what you'd see in a
- Xcylindrical mirror
- X.C
- Xnew[x,y] = old[a * X/A, r * Y/R] ; page 48
- X.E
- XThe image generated by
- X.C
- Xnew[x,y] = old{ (r/16)*16, (a/16)*16 } ; page 72
- X.E
- Xis very interesting, in that it is completely unrecognisable
- Xwhen viewed up close, but from a distance of a few metres it
- Xwill resolve into the original.
- X.C
- Xnew[x,y] = old{r, a + old{r,a)/8} ; page 68
- X.E
- XThis image is a swirl, but with the skew dependant on the
- Xbrightness of the current point.
- X.C
- Xnew[x,y] = x < X/2 ? old[x,y] : old[X-x,y]
- Xnew[x,y] = x > X/2 ? old[x,y] : old[X-x,y]
- X.E
- XThese transformations do a horizontal mirror reversal about the
- Xcentre of the image.
- XBecause faces are usually close to, but not exactly, centered,
- Xthis transform of a face can be interesting.
- X.C
- Xnew[x,y] = old[x+(x%32)-16, y] ; page 58
- Xnew[x,y] = old[x+((a+r/10)%32)-16, y]
- X.E
- XThese transforms applied to a face produce what looks like
- Xsomeone peering through a bathroom window.
- X.tr @@
- X.SH DRIVERS
- X.TP
- X.CW nulldev
- XThe null device driver is mainly for people with no graphics
- Xdisplay device for which a driver exists.
- XUsing this device, data for a PostScript or Epson printer can
- Xstill be generated.
- X.TP
- X.CW atariterm
- XThe atari driver is for use with "TERM", a multiplexing
- Xterminal program for the Atari ST, written by Peter Collinson
- Xof the University of Kent at Canterbury.
- XIt is not a driver for running native on an atari.
- X.TP
- X.CW kermit
- XThis is a driver for MS-Kermit 2.32 on an IBM PC, which is capable of
- Xemulating a Tektronix 4010. This provides three levels of contrast
- X(nothing, normal and bold).
- X.TP
- X.CW MGR
- XThis driver is for the Bell Core MGR window system. It is visually
- Xidentical to the SunView version, but is currently hardwired to
- Xmonochrome.
- X.TP
- X.CW NeWS
- XThis is the driver that will work with NeWS v1.1 and OpenWindows v1.0.
- XIt is also visually identical to the SunView version.
- X.TP
- X.CW pcturbo
- XThis is a driver for running popi native on a PC with
- XBorland's Turbo C compiler.
- XIt uses the graphics library supplied with Turbo C, which
- Xauto-detects most types of graphics display.
- XNo attempt at using a colourmap is done \- a single display
- Xdot is used for each image pixel, with simple dithering.
- XOnly directly accesible memory is used, which drastically
- Xrestricts the size of images that can be handled.
- X.TP
- X.CW SunView
- XThis driver is the initial version to work with the SunView
- Xgraphics package available on Sun Workstations.
- XThere is
- Xcurrently minimal functionality.
- XThe output is in 256 greyscales
- Xon colour machines, and an 8\*(Mu8 dither on monochrome screens.
- X.TP
- X.CW X11
- XA graphics implementation for use with MIT's X11 window system.
- XThis driver is visually identical to the SunView version.
- X.TP
- X.CW XView
- XA conversion of the SunView graphics driver to use the XView X11
- Xtoolkit. This driver is visually identical to the SunView version.
- X.SH SEE ALSO
- Xipscript(1L), imavg(1L).
- X.SH AUTHOR
- XGerald J. Holzmann, AT&T Bell Laboratories, Murray Hill, New
- XJersey.
- X.sp
- XModifications and additional functionality, Atari, PC, PostScript,
- XEpson and null drivers by
- XStephen Frede, Softway Pty Ltd, Australia.
- X.br
- XPopi maintainance, SunView, X11, NeWS, MGR and XView graphics drivers by
- XRich Burridge, Sun Microsystems, Australia.
- X.br
- XKermit graphics driver by
- XFrank Crawford, Q.H. Tours.
- X.br
- XAmiga graphics driver by
- XPeter Chubb, Softway Pty Ltd, Australia.
- X.br
- XApollo driver by
- XTim Lambert, University of New South Wales.
- X.SH BUGS
- XFunctions which require popen() (ie auto reading of compressed
- Xfiles and writing to pipes) don't work in the sequent
- Xmultiprocessor version.
- X.sp
- XProbably more \- please notify richb@sunaus.oz.au of any found.
- Funky_Stuff
- chmod 0444 popi.1 || echo "restore of popi.1 fails"
- set `wc -c popi.1`;Sum=$1
- if test "$Sum" != "23958"
- then echo original size 23958, current size $Sum;fi
- echo "x - extracting special.c (Text)"
- sed 's/^X//' << 'Funky_Stuff' > special.c &&
- X
- X/* @(#)special.c 1.11 89/12/12
- X *
- X * Special transformations used by the popi program.
- X *
- X * Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
- X * This version is based on the code in his Prentice Hall book,
- X * "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
- X * which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
- X *
- X * Permission is given to distribute these extensions, as long as these
- X * introductory messages are not removed, and no monies are exchanged.
- X *
- X * No responsibility is taken for any errors or inaccuracies inherent
- X * either to the comments or the code of this program, but if reported
- X * (see README file) then an attempt will be made to fix them.
- X */
- X
- X/* Special transformations from chapter 6 of BP.
- X *
- X * The way this is done is fairly nasty at the moment,
- X * but it does work.
- X */
- X
- X#ifndef AMIGA
- X# include <sys/types.h>
- X#endif /* AMIGA */
- X#include <ctype.h>
- X#include <time.h>
- X
- X#ifdef BSD
- X# include <sys/timeb.h>
- X#endif /* BSD */
- X#include "popi.h"
- X
- X#define GAMMA 7.5 /* default gamma for matte() */
- X#define TILESIZE 25 /* default tile size for tile() */
- X#define N 3
- X#define New src[CURNEW].pix
- X
- X/* prototypes for local functions */
- Xstruct SRC * parseimg P((void));
- Xbool parsefname P((void));
- Xvoid oil P((void));
- Xvoid shear P((void));
- Xvoid slice P((void));
- Xvoid tile P((void));
- Xvoid melt P((void));
- Xvoid matte P((void));
- Xvoid genps P((void));
- Xvoid genepson P((void));
- Xvoid list P((void));
- Xvoid readimg P((void));
- Xvoid writeimg P((void));
- Xvoid freeimg P((void));
- Xvoid displayimg P((void));
- Xvoid CloseLog P((void));
- Xvoid dolog P((void));
- Xvoid debug P((void));
- Xvoid undo P((void));
- Xvoid verbose P((void));
- Xvoid trunc P((void));
- X
- X/*
- X * convenience function, since most of these routines have
- X * an image as their 1st parameter.
- X */
- Xstatic struct SRC *
- Xparseimg()
- X{
- X lex();
- X
- X if (lat == '\n' || lat == ')')
- X {
- X pushback(lat);
- X return &src[CUROLD];
- X }
- X
- X if (lat != INAME)
- X {
- X SPRINTF(ErrBuf, "Expected image name");
- X error(ERR_PARSE);
- X return (struct SRC *) 0;
- X }
- X
- X return &src[lexval + 1];
- X}
- X
- Xstatic bool
- Xparsefname()
- X{
- X lex();
- X
- X if (lat == '\n')
- X pushback(lat);
- X
- X if (lat != FNAME)
- X {
- X SPRINTF(ErrBuf, "Expected file name");
- X error(ERR_PARSE);
- X return FALSE;
- X }
- X return TRUE;
- X}
- X
- Xstatic void
- Xoil()
- X{
- X register int x, y;
- X register int dx, dy;
- X pixel_t mfp;
- X static int *histo = 0;
- X struct SRC *srcp;
- X pixel_t **img;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X img = srcp->pix;
- X
- X if
- X (
- X histo == (int *) 0
- X &&
- X (histo = (int *) LINT_CAST(Emalloc((unsigned)Zsize * sizeof (int)))) == (int *) 0
- X )
- X return;
- X
- X if (disp_active)
- X disp_imgstart();
- X
- X for (y = N; y < Ysize-N; y++)
- X {
- X for (x = N; x < Xsize-N; x++)
- X {
- X for (dx = 0; dx < Zsize; dx++)
- X histo[dx] = 0;
- X for (dy = y-N; dy <= y+N; dy++)
- X for (dx = x-N; dx <= x+N; dx++)
- X histo[img[dy][dx]]++;
- X for (dx = dy = 0; dx < Zsize; dx++)
- X if (histo[dx] > dy)
- X {
- X dy = histo[dx];
- X mfp = (pixel_t) dx;
- X }
- X New[y][x] = mfp;
- X }
- X
- X if (disp_active)
- X disp_putline(New[y], y);
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X
- X if (disp_active)
- X disp_imgend();
- X
- X SwapOldNew();
- X}
- X
- X
- Xstatic void
- Xshear()
- X{
- X register int x, y, r;
- X int dx, dy;
- X static int *yshift = 0;
- X struct SRC *srcp;
- X pixel_t **img;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X
- X img = srcp->pix;
- X
- X if
- X (
- X yshift == 0
- X &&
- X (yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof(int)))) == 0
- X )
- X return;
- X
- X if (disp_active)
- X disp_imgstart();
- X
- X for (x = r = 0; x < Xsize; x++)
- X {
- X if (RANDOM % Zsize < 128)
- X r--;
- X else
- X r++;
- X yshift[x] = r;
- X }
- X
- X for (y = 0; y < Ysize; y++)
- X {
- X if (RANDOM % Zsize < 128)
- X r--;
- X else
- X r++;
- X
- X for (x = 0; x < Xsize; x++)
- X {
- X dx = x + r;
- X dy = y + yshift[x];
- X if (dx >= Xsize || dy >= Ysize || dx < 0 || dy < 0)
- X continue;
- X New[y][x] = img[dy][dx];
- X }
- X
- X if (disp_active)
- X disp_putline(New[y], y);
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X
- X if (disp_active)
- X disp_imgend();
- X
- X SwapOldNew();
- X}
- X
- X
- Xstatic void
- Xslice()
- X{
- X register int x, y, r;
- X int dx, dy;
- X struct SRC *srcp;
- X pixel_t **img;
- X static int *xshift = 0,
- X *yshift = 0;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X img = srcp->pix;
- X
- X if
- X (
- X xshift == 0
- X &&
- X (xshift = (int *) LINT_CAST(Emalloc((unsigned)Ysize * sizeof (int)))) == 0
- X )
- X return;
- X if
- X (
- X yshift == 0
- X &&
- X (yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof (int)))) == 0
- X )
- X return;
- X
- X if (disp_active)
- X disp_imgstart();
- X
- X for (x = dx = 0 ; x < Xsize; x++)
- X {
- X if (dx == 0)
- X {
- X r = (RANDOM & 63) - 32;
- X dx = 8 + RANDOM & 31;
- X }
- X else
- X dx--;
- X yshift[x] = r;
- X }
- X for (y = dy = 0; y < Ysize; y++)
- X {
- X if (dy == 0)
- X {
- X r = (RANDOM & 63) - 32;
- X dy = 8 + RANDOM & 31;
- X }
- X else
- X dy--;
- X xshift[y] = r;
- X }
- X
- X for (y = 0; y < Ysize; y++)
- X {
- X for (x = 0; x < Xsize; x++)
- X {
- X dx = x + xshift[y];
- X dy = y + yshift[x];
- X if (dx < Xsize && dy < Ysize && dx >= 0 && dy >= 0)
- X New[y][x] = img[dy][dx];
- X }
- X
- X if (disp_active)
- X disp_putline(New[y], y);
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X
- X if (disp_active)
- X disp_imgend();
- X
- X SwapOldNew();
- X}
- X
- X
- Xstatic void
- Xtile()
- X{
- X register int x,
- X y,
- X dx,
- X dy;
- X int ox,
- X oy,
- X nx,
- X ny,
- X TileSize = TILESIZE;
- X struct SRC *srcp;
- X pixel_t **img;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X img = srcp->pix;
- X
- X for (y = 0; y < Ysize-TileSize; y += TileSize)
- X {
- X for (x = 0; x < Xsize-TileSize; x += TileSize)
- X {
- X ox = (RANDOM & 31) - 16 ; /* Displacement. */
- X oy = (RANDOM & 31) - 16;
- X
- X for (dy = y; dy < y+TileSize; dy++)
- X for (dx = x; dx < x+TileSize; dx++)
- X {
- X nx = dx + ox;
- X ny = dy + oy;
- X if (nx >= Xsize || ny >= Ysize || nx < 0 || ny < 0)
- X continue;
- X New[ny][nx] = img[dy][dx];
- X }
- X }
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X
- X if (disp_active)
- X {
- X disp_imgstart();
- X for (y = 0; y < Ysize; y++)
- X disp_putline(New[y], y);
- X disp_imgend();
- X }
- X
- X SwapOldNew();
- X}
- X
- X
- X/*
- X * Note: affects source image in situ.
- X * Buffers not swapped after processing.
- X */
- Xstatic void
- Xmelt()
- X{
- X register int x,
- X y,
- X k,
- X NumPixels;
- X pixel_t val;
- X struct SRC *srcp;
- X pixel_t **img;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X img = srcp->pix;
- X
- X NumPixels = Xsize * Ysize;
- X for (k = 0; k < NumPixels; k++)
- X {
- X x = RANDOM % Xsize;
- X y = RANDOM % (Ysize - 1);
- X
- X while (y < Ysize-1 && img[y][x] <= img[y+1][x])
- X {
- X val = img[y][x];
- X img[y][x] = img[y+1][x];
- X img[y+1][x] = val;
- X y++;
- X }
- X disp_percentdone(k * 100 / (NumPixels-1));
- X }
- X if (disp_active)
- X {
- X disp_imgstart();
- X for (y = 0; y < Ysize; y++)
- X disp_putline(img[y], y);
- X disp_imgend();
- X }
- X}
- X
- X
- Xstatic void
- Xmatte()
- X{
- X struct SRC *srcp;
- X pixel_t **img;
- X double gamma;
- X register x,
- X y;
- X static pixel_t *lookup = (pixel_t *) 0;
- X static double lastgamma = 0.0;
- X
- X DEBUG((Debug, "matte()\n"));
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X img = srcp->pix;
- X
- X lex();
- X if (lat == '\n' || lat == ')')
- X {
- X gamma = GAMMA;
- X pushback(lat);
- X }
- X else
- X gamma = lexval + lexfract;
- X
- X if
- X (
- X lookup == 0
- X &&
- X (lookup = (pixel_t *) Emalloc((unsigned)Zsize)) == (pixel_t *) 0
- X )
- X return;
- X
- X if (lastgamma != gamma)
- X {
- X for (x = 0; x < Zsize; ++x)
- X lookup[x] = ((double)Zmax * pow(x / (double)Zmax, gamma) < 3.0)
- X ? Zmax : 0;
- X lastgamma = gamma;
- X }
- X
- X if (disp_active)
- X disp_imgstart();
- X for (y = 0; y < Ysize; y++)
- X {
- X for (x = 0; x < Xsize; x++)
- X New[y][x] = lookup[img[y][x]];
- X if (disp_active)
- X disp_putline(New[y], y);
- X disp_percentdone(y * 100 / (Ysize-1));
- X }
- X if (disp_active)
- X disp_imgend();
- X}
- X
- Xstatic void
- Xgenps()
- X{
- X int x,
- X y;
- X FILE *ostr;
- X struct SRC *srcp;
- X pixel_t **img,
- X *ip;
- X time_t time P((time_t *)),
- X clock;
- X#if unix
- X char *getlogin P((void));
- X#endif /* unix */
- X
- X if (!parsefname())
- X return;
- X
- X if ((ostr = EfopenW(text)) == NULL)
- X return;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X
- X img = srcp->pix;
- X clock = time((time_t *) 0);
- X
- X FPRINTF(ostr, "%%!PS-Adobe-1.0\n");
- X FPRINTF(ostr, "%%%%Title: popi bit image '%s'\n", srcp->str);
- X FPRINTF(ostr, "%%%%DocumentFonts:\n");
- X FPRINTF(ostr, "%%%%Creator: popi\n");
- X FPRINTF(ostr, "%%%%CreationDate: %s", ctime(&clock)); /* includes \n */
- X FPRINTF(ostr, "%%%%Pages: 1\n");
- X#if unix
- X FPRINTF(ostr, "%%%%For: %s\n", getlogin());
- X#endif /* unix */
- X FPRINTF(ostr, "%%%%EndComments\n");
- X FPRINTF(ostr, "clippath pathbbox pop pop translate\n");
- X FPRINTF(ostr, "clippath pathbbox pop exch pop exch sub dup scale\n");
- X FPRINTF(ostr, "/picstr %d string def\n", Xsize);
- X FPRINTF(ostr, "/doimage {\n");
- X FPRINTF(ostr, "%d %d %d [ %d 0 0 -%d 0 %d ]\n",
- X Xsize, Ysize, BITSPERPIXEL, Xsize, Ysize, Ysize);
- X FPRINTF(ostr, "{currentfile picstr readhexstring pop}image}bind def\n");
- X FPRINTF(ostr, "%%%%EndProlog\n%%%%Page 0 0\ndoimage\n");
- X
- X for(y = 0; y < Ysize; ++y)
- X {
- X ip = &img[y][0];
- X for(x = 0; x < Xsize; ++x)
- X {
- X if (x % 40 == 0) /* formatting only */
- X PUTC('\n', ostr);
- X FPRINTF(ostr, "%02x", *ip++);
- X }
- X PUTC('\n', ostr);
- X }
- X
- X FPRINTF(ostr, "showpage\n");
- X Efclose(ostr);
- X}
- X
- X/*
- X * Although this is set up to use one particular graphics mode
- X * of a 24-pin printer, everything should be generic enough
- X * that it can be changed to work with a different graphics
- X * mode on an 8-pin printer, just by changing a few numbers.
- X */
- Xstatic void
- Xgenepson()
- X{
- X struct SRC *srcp;
- X char *PinVals;
- X pixel_t *PinThresh,
- X ThreshStep;
- X FILE *ostr;
- X register int x;
- X register pixel_t **img;
- X int y,
- X yn;
- X int pin;
- X int BytesPerChunk,
- X PinsPerPixel,
- X BytesPerColumn,
- X yPixelsPerByte,
- X xPinsPerPixel,
- X yPinsPerPixel;
- X
- X if (parsefname() == 0)
- X return;
- X
- X if ((ostr = EfopenW(text)) == NULL)
- X return;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X
- X img = srcp->pix;
- X
- X /* printer specific */
- X xPinsPerPixel = 4;
- X yPinsPerPixel = 4;
- X BytesPerColumn = 24 / BITSINBYTE;
- X
- X PinsPerPixel = xPinsPerPixel * yPinsPerPixel;
- X BytesPerChunk = xPinsPerPixel * BytesPerColumn;
- X yPixelsPerByte = BITSINBYTE / yPinsPerPixel;
- X
- X /* Must be whole number of pixels (y direction) per byte. */
- X assert(yPinsPerPixel * yPixelsPerByte == BITSINBYTE);
- X
- X /* Reallocate these each time, as changing the print mode
- X * may change the sizes of these arrays.
- X */
- X if
- X (
- X (PinVals = Emalloc((unsigned)BytesPerChunk)) == 0
- X ||
- X (PinThresh = (pixel_t *) Emalloc((unsigned)PinsPerPixel * sizeof(pixel_t))) == 0
- X )
- X return;
- X
- X ThreshStep = (pixel_t) (Zsize / (PinsPerPixel + 1));
- X for (pin = 0; pin < PinsPerPixel; ++pin)
- X PinThresh[pin] = (pixel_t) ((pin + 1) * ThreshStep);
- X
- X for (y = 0; y < Ysize; y = yn)
- X {
- X
- X /* printer specific */
- X /*
- X * This print line is width Xsize pixels, and (Xsize * xPinsPerPixel)
- X * pin positions (dots on the page).
- X * No. of dots vertical is (BytesPerColumn * BITSINBYTE)
- X * which is yPinsPerPixel times the no. of image scanlines.
- X */
- X FPRINTF(ostr,
- X "\033*%c%c%c",
- X 39, /* 180 dpi in both directions */
- X (Xsize * xPinsPerPixel) % 256,
- X (Xsize * xPinsPerPixel) / 256
- X );
- X
- X for (x = 0; x < Xsize; ++x)
- X {
- X register int ycur;
- X int ByteCount,
- X xpin;
- X char *dp;
- X
- X /* Clear the PinVals array */
- X for
- X (
- X ByteCount = 0, dp = PinVals;
- X ByteCount < BytesPerChunk;
- X ++ByteCount
- X )
- X *dp++ = 0;
- X
- X dp = PinVals;
- X
- X /* For each byte-sized row of the print head,
- X * collect 1 pixel width of data.
- X */
- X for
- X (
- X ByteCount = 0, dp = PinVals, ycur = y;
- X ByteCount < BytesPerColumn;
- X ++ByteCount, dp += xPinsPerPixel
- X )
- X {
- X register unsigned char bit;
- X
- X yn = ycur + yPixelsPerByte;
- X if (yn > Ysize)
- X yn = Ysize;
- X
- X /* For the current byte row of the print-head
- X * (ie yPixelsPerByte image scanlines),
- X * collect a pixel width of data.
- X */
- X for (bit = 0x80; ycur < yn; ++ycur)
- X {
- X pixel_t val;
- X int ypin;
- X
- X val = img[ycur][x];
- X
- X /* Now use an appropriate no. of pins to simulate
- X * the greyscale value.
- X */
- X for
- X (
- X ypin = 0, pin = 0;
- X ypin < yPinsPerPixel;
- X ++ypin
- X )
- X {
- X for (xpin = 0; xpin < xPinsPerPixel; ++xpin, ++pin)
- X {
- X if (val < PinThresh[pin])
- X dp[xpin] |= bit;
- X }
- X /* xpin == xPinsPerPixel */
- X bit >>= 1;
- X }
- X /* ypin == YpinsPerPixel */
- X }
- X /* ycur == y */
- X }
- X /* ByteCount == BytesPerColumn */
- X
- X /* We have set up enough columns for a single pixel in
- X * the x direction. Now print them in the correct order.
- X */
- X for (xpin = 0; xpin < xPinsPerPixel; ++xpin)
- X {
- X for (ByteCount = 0; ByteCount < BytesPerColumn; ++ByteCount)
- X {
- X PUTC(PinVals[ByteCount * xPinsPerPixel + xpin], ostr);
- X }
- X }
- X /* xpin == xPinsPerPixel */
- X }
- X /* x == Xsize */
- X
- X /* Printer specific */
- X FPRINTF(ostr, "\033J%c\r", 24);
- X }
- X /* y == Ysize */
- X
- X Efclose(ostr);
- X free(PinVals);
- X free((char *) PinThresh);
- X}
- X
- Xstatic void
- Xlist()
- X{
- X showfiles();
- X}
- X
- X/*
- X * #read "filename" [imagename]
- X */
- Xstatic void
- Xreadimg()
- X{
- X char filename[512],
- X *imgname = (char *) 0;
- X
- X if (parsefname() == 0)
- X return;
- X
- X STRCPY(filename, text);
- X
- X lex();
- X
- X if (lat == '\n' || lat == ')')
- X {
- X pushback(lat);
- X }
- X else if (lat != NAME && lat != INAME)
- X {
- X SPRINTF(ErrBuf, "Expected image name");
- X error(ERR_PARSE);
- X }
- X else
- X imgname = text;
- X
- X getpix(filename, imgname);
- X}
- X
- Xstatic void
- Xwriteimg()
- X{
- X struct SRC *srcp;
- X
- X if (parsefname() == 0)
- X return;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X
- X putpix(srcp, text);
- X}
- X
- Xstatic void
- Xfreeimg()
- X{
- X struct SRC *srcp;
- X
- X if ((srcp = parseimg()) == (struct SRC *) 0)
- X return;
- X
- X if (srcp == &src[CUROLD] || srcp == &src[CURNEW])
- X {
- X SPRINTF(ErrBuf, "Cannot free 'old' or 'new'");
- X error(0);
- X return;
- X }
- X
- X ImgFree(srcp);
- X}
- X
- Xstatic void
- Xdisplayimg()
- X{
- X pixel_t **img;
- X int y;
- X
- X
- X lex();
- X
- X if (lat == '+')
- X {
- X disp_active = 1;
- X return;
- X }
- X if (lat == '-')
- X {
- X disp_active = 0;
- X return;
- X }
- X if (lat == '\n')
- X {
- X pushback(lat);
- X img = src[CUROLD].pix;
- X }
- X else if (lat == INAME)
- X img = src[lexval + 1].pix;
- X else if (lat == NEW)
- X img = src[CURNEW].pix;
- X else
- X {
- X SPRINTF(ErrBuf, "Expected +, - or image name");
- X error(ERR_PARSE);
- X return;
- X }
- X
- X disp_imgstart();
- X
- X for (y = 0; y < Ysize; y++)
- X disp_putline(img[y], y);
- X
- X disp_imgend();
- X}
- X
- Xstatic void
- XCloseLog()
- X{
- X if (LogStr == NULL)
- X return;
- X
- X FPRINTF(LogStr, "\n---\n");
- X FCLOSE(LogStr);
- X LogStr = NULL;
- X}
- X
- Xvoid
- XOpenLog()
- X{
- X time_t time(),
- X clock;
- X
- X CloseLog();
- X
- X if ((LogStr = fopen(LogFile, "a")) == NULL)
- X {
- X SPRINTF(ErrBuf,
- X "Can't open log file '%s' - logging is off",
- X LogFile);
- X error(ERR_SYS);
- X return;
- X }
- X
- X clock = time((time_t *) 0);
- X FPRINTF(LogStr, "==>> %s", ctime(&clock)); /* includes '\n' */
- X}
- X
- Xstatic void
- Xdolog()
- X{
- X static char *buf = (char *) 0;
- X
- X lex();
- X
- X if (lat == '+')
- X OpenLog();
- X else if (lat == '-')
- X CloseLog();
- X else if (lat == FNAME)
- X {
- X if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
- X return;
- X STRCPY(buf, text);
- X LogFile = buf;
- X OpenLog();
- X }
- X else
- X pushback(lat);
- X
- X if (LogStr)
- X PRINTF("Logging is active on file '%s'\n", LogFile);
- X else
- X PRINTF("Logging is off\n");
- X}
- X
- Xstatic void
- Xdebug()
- X{
- X static char *buf = (char *) 0;
- X
- X lex();
- X
- X if (lat == '+')
- X OpenLog();
- X else if (lat == '-')
- X CloseLog();
- X else if (lat == FNAME)
- X {
- X if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
- X return;
- X STRCPY(buf, text);
- X LogFile = buf;
- X OpenLog();
- X }
- X else
- X pushback(lat);
- X
- X if (LogStr)
- X PRINTF("Logging is active on file '%s'\n", LogFile);
- X else
- X PRINTF("Logging is off\n");
- X}
- X
- Xstatic char *HelpMsg[] =
- X{
- X "binary ops: ** * / % + - << >> < > >= <= == != & ^ | && ||",
- X "funcs: sin(deg) cos(deg) atan(y, x) log(val) sqrt(val) abs(val) rand()",
- X "values: x y r a X Y R A Z",
- X "special funcs",
- X "\t#read \"filename\"",
- X "\t#write \"filename\"",
- X "\t#genps \"filename\" [image]",
- X "\t#display [image]",
- X "\t#display +",
- X "\t#display -",
- X (char *) 0
- X};
- X
- Xvoid
- Xhelp()
- X{
- X PrStrs(HelpMsg);
- X}
- X
- Xstatic void
- Xundo()
- X{
- X SwapOldNew();
- X}
- X
- Xstatic void
- Xverbose()
- X{
- X lex();
- X
- X if (lat == '+')
- X Verbose = 1;
- X else if (lat == '-')
- X Verbose = 0;
- X else
- X pushback(lat);
- X
- X PRINTF("Verbose is %s\n", Verbose ? "on" : "off");
- X}
- X
- Xstatic void
- Xtrunc()
- X{
- X lex();
- X
- X if (lat == '+')
- X Truncate = 1;
- X else if (lat == '-')
- X Truncate = 0;
- X else
- X pushback(lat);
- X
- X PRINTF("Truncation is %s\n", Truncate ? "on" : "off");
- X}
- X
- Xstruct SpecialOp
- X{
- X char *name;
- X void (*func) P((void));
- X};
- X
- Xstatic struct SpecialOp SpecialOps[] =
- X{
- X { "matte", matte },
- X { "oil", oil },
- X { "slice", slice },
- X { "shear", shear },
- X { "tile", tile },
- X { "melt", melt },
- X { "read", readimg },
- Funky_Stuff
- echo "End of part 4"
- echo "File special.c is continued in part 5"
- echo "5" > s2_seq_.tmp
- exit 0
-
-