home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume9 / popi / part04 < prev    next >
Encoding:
Internet Message Format  |  1991-03-08  |  45.6 KB

  1. From: richb@sunaus.sun.oz.AU (Rich Burridge)
  2. Newsgroups: comp.sources.misc
  3. Subject: v09i050: popi, The Digital Darkroom, Part04/09
  4. Message-ID: <2784@basser.oz>
  5. Date: 12 Dec 89 23:46:51 GMT
  6. Approved: john@cs.su.oz.AU (John Mackin - comp.sources.misc)
  7.  
  8. Posting-number: Volume 9, Issue 50
  9. Submitted-by: Rich Burridge <richb@sunaus.sun.oz.AU>
  10. Archive-name: popi/part04
  11.  
  12. ---- Cut Here and unpack ----
  13. #!/bin/sh
  14. # this is part 4 of a multipart archive
  15. # do not concatenate these parts, unpack them in order with /bin/sh
  16. # file run.c continued
  17. #
  18. CurArch=4
  19. if test ! -r s2_seq_.tmp
  20. then echo "Please unpack part 1 first!"
  21.      exit 1; fi
  22. ( read Scheck
  23.   if test "$Scheck" != $CurArch
  24.   then echo "Please unpack part $Scheck next!"
  25.        exit 1;
  26.   else exit 0; fi
  27. ) < s2_seq_.tmp || exit 1
  28. echo "x - Continuing file run.c"
  29. sed 's/^X//' << 'Funky_Stuff' >> run.c
  30. X        ++rp;
  31. X    }
  32. X
  33. X#if    SEQPAR
  34. X    if (m_myid == 0)
  35. X#endif    /* SEQPAR */
  36. X    disp_percentdone(y * 100 / (Ysize-1));
  37. X    }
  38. X
  39. X#if 0
  40. X    if (nrange != 0)
  41. X    FPRINTF(stderr,
  42. X        "Total of %d range errors corrected\n",
  43. X        nrange);
  44. X#endif
  45. X}
  46. X
  47. Xvoid
  48. Xrun()
  49. X{
  50. X    int    y;
  51. X#if    SEQPAR
  52. X    static int    parked = 0;
  53. X
  54. X    if (parked)
  55. X    m_rele_procs();
  56. X    m_fork(prun);
  57. X    m_kill_procs();    /* For some reason, parking doesn't work properly ...
  58. X    m_park_procs();
  59. X    parked = 1;        /* so it can be released above */
  60. X#else    /* ! SEQPAR */
  61. X    prun();
  62. X#endif    /* ! SEQPAR */
  63. X
  64. X    disp_percentdone(100);    /* Can rely on '100' to terminate */
  65. X
  66. X    if (disp_active)
  67. X    {
  68. X    disp_imgstart();
  69. X    for (y = 0; y < Ysize; ++y)
  70. X        disp_putline(src[CURNEW].pix[y], y);
  71. X    disp_imgend();
  72. X    }
  73. X
  74. X    SwapOldNew();
  75. X}
  76. Funky_Stuff
  77. echo "File run.c is complete"
  78. chmod 0444 run.c || echo "restore of run.c fails"
  79. set `wc -c run.c`;Sum=$1
  80. if test "$Sum" != "8692"
  81. then echo original size 8692, current size $Sum;fi
  82. echo "x - extracting popi.prj (Text)"
  83. sed 's/^X//' << 'Funky_Stuff' > popi.prj &&
  84. X
  85. X
  86. XEXPR
  87. XIBMPC
  88. XIO
  89. XLEX
  90. XMAIN
  91. XPOLAR
  92. XRUN
  93. XSPECIAL
  94. Xgraphics.lib
  95. Funky_Stuff
  96. chmod 0444 popi.prj || echo "restore of popi.prj fails"
  97. set `wc -c popi.prj`;Sum=$1
  98. if test "$Sum" != "56"
  99. then echo original size 56, current size $Sum;fi
  100. echo "x - extracting powerc.prj (Text)"
  101. sed 's/^X//' << 'Funky_Stuff' > powerc.prj &&
  102. X# Project file for Mix Software's Power C Compiler
  103. X# Compile with "pc powerc.prj"
  104. Xmain    popi.h main.c
  105. Xexpr    popi.h expr.c
  106. Xio    popi.h io.c
  107. Xlex    popi.h lex.c
  108. Xpolar    popi.h polar.c
  109. Xrun    popi.h run.c
  110. Xspecial    popi.h special.c
  111. Xibmpc    popi.h ibmpc.c
  112. Xpopi.exe    main expr io lex polar run special ibmpc
  113. Funky_Stuff
  114. chmod 0444 powerc.prj || echo "restore of powerc.prj fails"
  115. set `wc -c powerc.prj`;Sum=$1
  116. if test "$Sum" != "286"
  117. then echo original size 286, current size $Sum;fi
  118. echo "x - extracting popi.1 (Text)"
  119. sed 's/^X//' << 'Funky_Stuff' > popi.1 &&
  120. X.\" @(#)popi.1 1.8 89/12/11
  121. X.\"OPTIONS man
  122. X.TH POPI 1L "12 December 1989"
  123. X.tr @"
  124. X.\"These macros always explicitly return to font 1, rather than the
  125. X.\"previous font, because previous may have been altered.
  126. X.de C
  127. X.\" Start constant width
  128. X.sp 0.5
  129. X.nf
  130. X.po +2c
  131. X.ft CW
  132. X..
  133. X.\" End constant width
  134. X.de E
  135. X.sp 0.5
  136. X.po
  137. X.ft 1
  138. X.fi
  139. X..
  140. X.de CW
  141. X\&\f(CW\\$1\&\f1\\$2\&
  142. X..
  143. X.ie t .ds Mu \(mu
  144. X.el .ds Mu x
  145. X.ie t .ds +- \(+-
  146. X.el .ds +- +-
  147. X.\"-------------------------------------------------------------------------
  148. X.SH NAME
  149. Xpopi \- perform interactive digital image transformations
  150. X.SH SYNOPSIS
  151. X.B "popi [option] ... [file] ..."
  152. X.SH DESCRIPTION
  153. X.I Popi
  154. Xis a program which allows arbitrary transformations to be
  155. Xinteractively applied to digital images.
  156. XIt is based on the program described in "Beyond Photography
  157. X\- The Digital Darkroom" by Gerald J. Holzmann.
  158. X.P
  159. XThe meanings of the available command line options are as follows:
  160. X.TP
  161. X.BI \-V
  162. XPrint program version identification message and exit.
  163. X.TP
  164. X.BI \-x Width
  165. XSet the image width (number of pixels per scanline) to
  166. X.I Width .
  167. X.TP
  168. X.BI \-y Height
  169. XSet the image height (number of scanlines) to
  170. X.I Height .
  171. X.TP
  172. X.BI \-v+
  173. XSet the verbose flag on.
  174. XBe chatty about a number of things.
  175. X.TP
  176. X.BI \-v\-
  177. XTurn the verbose flag off.
  178. XBe silent about everything except error messages.
  179. X.TP
  180. X.BI \-a+
  181. XTurn auto-display on.
  182. XAfter each image transformation, the image will be displayed.
  183. XEquivalent to the
  184. X.CW "#display +"
  185. Xcommand.
  186. X.TP
  187. X.BI \-a\-
  188. XTurn auto-display off.
  189. XEquivalent to the
  190. X.CW "#display \-"
  191. Xcommand.
  192. XImages can still be displayed explicitly with the
  193. X.CW "#display \f2image\fP"
  194. Xcommand.
  195. X.TP
  196. X.BI \-p [ncpus]
  197. XOn a Sequent multiprocessor, use the specified number of cpus
  198. Xto perform the transform.
  199. XIf this option is given without a number, the maximum number
  200. Xavailable is used.
  201. XThis option has no effect on uniprocessor computers.
  202. X.TP
  203. X.BI \-l [logfile]
  204. XEnables logging of all input, error messages, and some
  205. Xresponses.
  206. XLogging is done on the named file, or the file "popi.log" if no
  207. Xname is given.
  208. XThe
  209. X.CW "#logfile"
  210. Xcommand may also be used to turn logging on and off.
  211. X.P
  212. XAn image transform is described by a transform statement.
  213. XThe statement basically takes the form
  214. X.C
  215. X\f2dest\fP = \f2expression\fP
  216. X.E
  217. Xwhere
  218. X.I dest
  219. Xindicates the new image and
  220. X.I expression
  221. Xdescribes a transformation.
  222. XThis statement is executed over the range of image
  223. Xcoordinates.
  224. XFor a 512 \*(Mu 512 image, it will be executed 262144 times.
  225. XAn image is normally referenced in a statement by its name
  226. Xand an index.
  227. XA cartesian index is specified by using the x and y
  228. Xcoordinates in square brackets after the image name.
  229. XThus
  230. X.CW dmr[0,0]
  231. Xis the top left pixel in the image named
  232. X.CW dmr .
  233. XPolar coordinates may be specified by giving a radius and
  234. Xangle (in degrees) in curly brackets.
  235. XThus
  236. X.CW dmr{0,0}
  237. Xrefers to the centre pixel in the
  238. Ximage.
  239. XThe symbols
  240. X.CW x
  241. Xand
  242. X.CW y
  243. Xmay appear in the transform statement.
  244. XThese take on values corresponding to a different pixel each
  245. Xtime the transform is executed.
  246. XInternally the algorithm is as follows
  247. X.sp 0.5
  248. X.nf
  249. Xfor y varying from 0 to Y
  250. X    for x varying from 0 to X
  251. X        execute transform statement
  252. X.sp 0.5
  253. X.fi
  254. Xwhere
  255. X.CW Y
  256. Xis the maximum y coordinate and
  257. X.CW X
  258. Xis the maximum x coordinate.
  259. XThe image size can be set on the command line as described
  260. Xlater.
  261. X.P
  262. XThe value of a pixel varies from 0 to 255 in the current
  263. Ximplementation.
  264. XAny value outside this range is treated as modulo 256 when
  265. Xbeing stored in an image (ie. it wraps around).
  266. XLow numeric values represent dark colours, while large values
  267. Xrepresent light colours.
  268. XA simple transform statement to set an image to completely
  269. Xblack would be
  270. X.C
  271. Xnew[x,y] = 0        ; set image to black
  272. X.E
  273. XThe name
  274. X.CW new
  275. Xis one of the two default images always maintained internally.
  276. XThe other is
  277. X.CW old .
  278. XThe images referred to by these names are swapped after each
  279. Xoperation, so a succession of transforms may modify the "old"
  280. Ximage to produce a "new" image.
  281. XThus the statement
  282. X.C
  283. Xnew[x,y] = old[x,y] / 2      ; darken image
  284. X.E
  285. Xwill reduce all the pixel intensity values by a half,
  286. Xdarkening the existing image.
  287. XThe semicolon (`;') character introduces a comment.
  288. XAnything from this to the end of the line is ignored.
  289. X.P
  290. XAll the standard arithmetic, relational and boolean operators
  291. Xfrom the C language are available, with precedence generally
  292. Xas per the C language.
  293. XSome additional operators, predefined variables and math
  294. Xfunctions are also available.
  295. X.P
  296. XHere is a listing of the available symbols and their
  297. Xmeanings.
  298. X.TP
  299. X\f2name\fP
  300. XRefers to an image name.
  301. XIf not followed by index brackets, the index
  302. X.CW "[x,y]"
  303. Xis assumed.
  304. XThe currently available names are those shown by the
  305. X.CW #list
  306. Xdisplay, and also
  307. X.CW old
  308. Xand
  309. X.CW new .
  310. X.TP
  311. X.CW $\f2n\fP
  312. XWhere \f2n\fP is a digit, this is an alternative method of
  313. Xreferring to an image.
  314. XIn fact this may be the only method if the image name contains
  315. Xpunctuation characters.
  316. XThe
  317. X.CW #list
  318. Xcommand shows the correspondence between image names and this
  319. Xform of reference.
  320. X.TP
  321. X.CW X
  322. XThe maximum x coordinate value.
  323. XThis is one less than the number of pixels per scanline
  324. X(image width), which may be set with the
  325. X.B \-x
  326. Xcommand line option.
  327. X.TP
  328. X.CW Y
  329. XThe maximum y coordinate value.
  330. XThis is one less than the number of scanlines (the height of
  331. Xthe image), which may be set with the
  332. X.B \-y
  333. Xcommand line option.
  334. X.TP
  335. X.CW x
  336. XThe current cartesian x coordinate.
  337. XVaries from 0 (left of image) to 
  338. X.CW X
  339. X(right of image).
  340. X.TP
  341. X.CW y
  342. XThe current cartesian y coordinate.
  343. XVaries from 0 (top of image) to
  344. X.CW Y
  345. X(bottom of image).
  346. X.TP
  347. X.CW r
  348. XThe radius component of the polar coordinate which corresponds to the
  349. Xcurrent cartesian (x,y) coordinate.
  350. XThis is equivalent to
  351. X.CW "sqrt(x*x + y*y)"
  352. Xwith a translation of the origin.
  353. X.TP
  354. X.CW a
  355. XThe angle component of the polar coordinate which corresponds to the
  356. Xcurrent cartesian (x,y) coordinate.
  357. XThis is equivalent to (and a shorthand for)
  358. X.CW "atan(y/x)" .
  359. X.sp
  360. XNote that the first time in a popi session you use an expression with either
  361. X.CW r
  362. Xor
  363. X.CW a
  364. Xin it, you may notice an extra delay before the image
  365. Xtransformation begins.
  366. XThis is due to precalculation of an array of polar coordinates
  367. Xthat happens the first time you use one.
  368. X.TP
  369. X.CW R
  370. XThe maximum radius value of a polar coordinate.
  371. X.TP
  372. X.CW A
  373. XThe maximum angle value of a polar coordinate (this is just 360).
  374. X.TP
  375. X.CW Z
  376. XThe maximum intensity value of a pixel (corresponding to white).
  377. XCurrently, this is always 255.
  378. X.TP
  379. X.CW **
  380. XThe exponentiation (raise to the power) operator.
  381. XThe expression
  382. X.CW "x ** 2"
  383. Xmeans x squared (x * x).
  384. X.TP
  385. X.CW *
  386. XThe multiplication operator.
  387. XThis has a higher precedence than division to avoid underflow
  388. Xin expressions with multiplication and division, since normally
  389. Xexpressions are evaluated as integers.
  390. X.TP
  391. X.CW /
  392. XInteger division.
  393. XIf the divisor is 0, the result is set to Z.
  394. X.TP
  395. X.CW %
  396. XModulo.
  397. XIf the divisor (right hand operand) is 0, the result is set to 0.
  398. X.TP
  399. X.CW "+"
  400. XAddition.
  401. X.TP
  402. X.CW "\-"
  403. XSubtraction.
  404. XThis may be a unary or a binary operator.
  405. X.TP
  406. X.CW "<<"
  407. XLeft shift.
  408. XThe left operand is shifted left the number of bits specified by the
  409. Xright operand.
  410. X.TP
  411. X.CW ">>"
  412. XRight shift.
  413. XThe left operand is shifted right the number of bits specified by the
  414. Xright operand.
  415. X.TP
  416. X.CW ">"
  417. XGreater than.
  418. XAs with all the relational operators, if the specified relation between
  419. Xthe operands is true, the result is 1, otherwise the result is 0.
  420. X.TP
  421. X.CW "<"
  422. XLess than.
  423. X.TP
  424. X.CW ">="
  425. XGreater than or equal to.
  426. X.TP
  427. X.CW "<="
  428. XLess than or equal to.
  429. X.TP
  430. X.CW "=="
  431. XTest for equality.
  432. X.TP
  433. X.CW "!="
  434. XNot equal to.
  435. X.TP
  436. X.CW "&"
  437. XBitwise (arithmetic) AND operator.
  438. X.TP
  439. X.CW "^"
  440. XBitwise exclusive OR (XOR) operator.
  441. X.TP
  442. X.CW "|"
  443. XBitwise (arithmetic) OR operator.
  444. X.TP
  445. X.CW "&&"
  446. XLogical AND operator.
  447. XThe result is 1 if both of the operands are true (non-zero);
  448. Xotherwise the result is 0.
  449. XUnlike the && operator of the C language, this operator is currently not
  450. Xconditional.
  451. XBoth operands are always evaluated.
  452. X.TP
  453. X.CW "||"
  454. XLogical OR operator.
  455. XThe result is 1 if both either (or both) of the operands are true
  456. X(non-zero); otherwise the result is 0.
  457. XUnlike the || operator of the C language, this operator is currently not
  458. Xconditional.
  459. XBoth operands are always evaluated.
  460. X.TP
  461. X.CW sin(\f2expr\fP)
  462. XThis gives the value of the trigonometric sine of the expression,
  463. Xmultiplied by Z.
  464. XThis is required because all operations are performed with integers.
  465. X.TP
  466. X.CW cos(\f2expr\fP)
  467. XThis gives the value of the trigonometric cosine of the expression,
  468. Xmultiplied by Z.
  469. XThis is required because all operations are performed with integers.
  470. X.TP
  471. X.CW atan(\f2y-expr\fP,\f2x-expr\fP)
  472. XThis returns the trigonometric arctangent (inverse tangent) of
  473. X.I y-expr/x-expr
  474. Xin degrees (ie the value returned will be between 0 and 360).
  475. X.TP
  476. X.CW log(\f2expr\fP)
  477. XReturns the natural logarithm of the expression.
  478. X.TP
  479. X.CW sqrt(\f2expr\fP)
  480. XReturns the square root of the expression.
  481. X.TP
  482. X.CW rand()
  483. XReturns a positive random number.
  484. XThis will usually be used with the modulo or bitwise AND
  485. Xoperator to restrict the range of the result.
  486. XFor example,
  487. X.C
  488. Xnew[x,y] = old[x,y] + rand() % 20 \- 10
  489. X.E
  490. Xwill adjust the brightness levels of each pixel in the old image by a
  491. Xrandom amount (up to 10 levels brighter or darker).
  492. X.\".TP
  493. X.\".CW rand(\f2expr\fP)
  494. X.\"Returns a positive random number between 0 and the value of
  495. X.\"the parameter.
  496. X.\"This is provided as a more efficient alternative to
  497. X.\".CW "rand() % \f2expr\fP"
  498. X.\"The previous example could thus be rewritten as:
  499. X.\".C
  500. X.\"new[x,y] = old[x,y] + rand(20) \- 10
  501. X.\".E
  502. X.P
  503. XAs well as allowing transformation statements, a number of special
  504. Xcommands, each starting with a
  505. X.CW #
  506. Xcharacter, are allowed.
  507. XThese are described here.
  508. X.TP
  509. X.CW "#read @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
  510. XRead a raw data file into the named image.
  511. XIf no image name is specified, the name is derived from the base name
  512. Xcomponent of the filename.
  513. XIf the name already exists, that image is overwritten in memory,
  514. Xotherwise a new image is created.
  515. XIf the filename does not exist, but the same name with a ".Z"
  516. Xsuffix does exist, it is assumed that the file is compressed
  517. Xand the "zcat" program is used to read the compressed image.
  518. XNote that when the image name defaults to the file name, only
  519. Xthe basename (portion after the last '/' character, if any) is
  520. Xused to name the image.
  521. XIf this resulting name starts with a digit, or contains any
  522. Xcharacters other than alphabetic, digits and the underscore,
  523. Xyou will not be able to reference the image by name, but will
  524. Xhave to use the alternative "$n" syntax.
  525. X.TP
  526. X.CW "#write @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
  527. XWrite a raw data file from the named image.
  528. XThe image name is optional, and
  529. Xif not specified, image "old" is used.
  530. XIf the first character of the filename is `|', the rest of the filename
  531. Xis interpreted as a command to be run, with the raw image data being fed
  532. Xto it as standard input.
  533. X.TP
  534. X.CW "#list"
  535. XAll the named images (other than "old" and "new" are listed).
  536. X.TP
  537. X.CW "#genps @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
  538. XGenerate postscript to produce the image.
  539. XThe image name is optional, and
  540. Xif not specified, image "old" is used.
  541. XThe image will be scaled to fit whatever paper size is being used.
  542. XAs with the
  543. X.CW #write
  544. Xcommand, if the first character of the filename is a `|' symbol, the
  545. Xrest of the string will be treated as a command to be executed, with the
  546. Xpostscript being piped to its standard input.
  547. XThis is convenient for printing images on a PostScript printer.
  548. X.TP
  549. X.CW #undo
  550. XThe
  551. X.CW old
  552. Xand
  553. X.CW new
  554. Ximages are swapped.
  555. XThis has the effect of restoring the image that existed
  556. Xbefore the last transformation.
  557. X.TP
  558. X.CW "#genepson @\f2filename\fP@ \f1[\fP\f2image-name\fP\f1]\fP"
  559. XGenerate data for an Epson (or compatible) printer to produce
  560. Xthe image.
  561. XThe image name is optional, and if not specified, image "old" is used.
  562. XUnder MSDOS, the device name can be used directly (eg "PRN").
  563. X.sp
  564. XThe existing code is for a 24-pin printer such as the LQ-500.
  565. XTo generate data for an 8-pin printer requires a couple of
  566. Xminor modifications to function
  567. X.CW genepson()
  568. Xin file
  569. X.CW special.c .
  570. X.TP
  571. X.CW #undo
  572. XThe
  573. X.CW old
  574. Xand
  575. X.CW new
  576. Ximages are swapped.
  577. XThis has the effect of restoring the image that existed
  578. Xbefore the last transformation.
  579. X.TP
  580. X.CW "#display \f2image-name\fP"
  581. XThe named image will be displayed.
  582. XThis is the fastest way to display an image, and works regardless of the
  583. Xstate of auto-display.
  584. X.TP
  585. X.CW "#display +"
  586. XTurn auto-display on (equivalent to the command-line option
  587. X.B \-a+ ).
  588. X.TP
  589. X.CW "#display \-"
  590. XTurn auto-display off (equivalent to the command-line option
  591. X.B \-a\- ).
  592. X.TP
  593. X.CW "#truncate +"
  594. XAll assignments to an image with values outside the range
  595. X.CW 0
  596. Xto
  597. X.CW Z
  598. Xwill be truncated to the appropriate boundary, instead of
  599. Xwrapping as described in the book.
  600. XAn example of using this feature would be for a simplistic
  601. Xlightening of an image by adding a constant value.
  602. XNormally, very white areas would wrap around and become black,
  603. Xbut enabling truncation prevents this.
  604. X.TP
  605. X.CW "#truncate \-"
  606. XAll assignments to an image will be done modulo
  607. X.CW "(Z+1)" .
  608. XThis is the default.
  609. X.TP
  610. X.CW "#verbose +"
  611. XTurn on verbose mode.
  612. XEquivalent to the
  613. X.CW "\-v+" command line option.
  614. XCertain warning messages will be printed.
  615. XThis turns on the "percent done" feature of some drivers (on
  616. Xothers it is always active).
  617. X.TP
  618. X.CW "#truncate"
  619. XReport whether truncation is currently in effect or not.
  620. X.TP
  621. X.CW "#verbose \-"
  622. XTurn off verbose mode.
  623. XEquivalent to the
  624. X.CW "\-v\-" command line option.
  625. X.TP
  626. X.CW "#verbose"
  627. XReport the state of the verbose flag.
  628. X.TP
  629. X.CW "#logfile +"
  630. XEnable logging on the current log file (default "popi.log").
  631. XIf logging is already enabled, the file is closed and re-opened
  632. Xwith a new timestamp appended.
  633. X.TP
  634. X.CW "#logfile \-"
  635. XDisable logging"
  636. X.TP
  637. X.CW "#logfile @\f2filename\fP@"
  638. XEnable logging on the specified file.
  639. X.sp
  640. XWhenever a log file is opened, it is always opened in append
  641. Xmode, so existing data is never truncated.
  642. XUpon opening a log file, a timestamp is written.
  643. XAll user input is logged, along with error messages and some
  644. Xprogram responses.
  645. X.TP
  646. X.CW "#free \f2imagename\fP"
  647. XThe memory associated with the named image is freed.
  648. XAny further access to this image becomes impossible.
  649. XThis command may be useful in situations where memory is very
  650. Xlimited, such as a PC.
  651. X.P
  652. XThe remaining special commands are used to obtain special built-in
  653. Xtransformations, as described in Chapter 6 of "Beyond Photography".
  654. XIn each of these cases, the image name is optional, and defaults to
  655. X"old".
  656. XIn each case (except for
  657. X.CW #melt ),
  658. Xthe result is stored in "new", and then "old" and "new" are swapped as
  659. Xusual.
  660. XIn the case of
  661. X.CW #melt ,
  662. Xthe transformation is done in place and no swap occurs.
  663. X.TP
  664. X.CW "#oil \f2image-name\fP"
  665. X.TP
  666. X.CW "#shear \f2image-name\fP"
  667. X.TP
  668. X.CW "#slice \f2image-name\fP"
  669. X.TP
  670. X.CW "#tile \f2image-name\fP"
  671. X.TP
  672. X.CW "#melt \f2image-name\fP"
  673. X.TP
  674. X.CW "#matte \f2image-name\fP \f2gamma\fP"
  675. XIn this case,
  676. X.I gamma
  677. Xis an optional floating point number (defaults to 7.5).
  678. XSee the book for details.
  679. X.SH DIFFERENCES
  680. XThere are a number of differences between the Pico interpreter, for
  681. Xwhich the examples in the book are written, and the Popi interpreter as
  682. Ximplemented here.
  683. X.P
  684. XInteger evaluation stack.
  685. XThe current version of the interpreter has an integer evaluation stack.
  686. XFor this reason, the
  687. X.CW sin()
  688. Xand
  689. X.CW cos()
  690. Xfunctions, have their results multiplied by Z automatically in order to
  691. Xbe significant.
  692. XA future version of the interpreter will provide the option for a
  693. Xfloating point stack, and a syntax which will handle both cases.
  694. X.P
  695. XPolar coordinates.
  696. XIn the book, both cartesian and polar coordinates are specified with
  697. Xsquare brackets.
  698. XThe decision of whether to interpret the indices as polar or cartesian
  699. Xis based on context;
  700. Xif the symbols
  701. X.CW r
  702. Xand
  703. X.CW a
  704. Xare used in the index expressions, the coordinates are interpreted as
  705. Xpolar, otherwise they are interpreted as rectangular.
  706. XThus, in order to use a radius or angle in a cartesian coordinate
  707. Xexpression, it must be cast, as is done on page 48 of the book.
  708. XBy providing a separate syntax for polar and cartesian coordinate
  709. Xreferences, the problem never occurs.
  710. X.SH EXAMPLES
  711. XThese examples are mainly taken from the book, with syntax modifications
  712. Xwhere required.
  713. XThe images in the book are usually 1000 \*(Mu 1000 pixels.
  714. XTo produce the same results on a smaller image, you may need to multiply
  715. Xany occurences of
  716. X.CW x ,
  717. X.CW y
  718. Xand
  719. X.CW r
  720. Xby an appropriate scaling factor.
  721. XThe first example image generation in the book is
  722. X.C
  723. Xnew[x,y] = x + y  ; page 17 (3.1)
  724. X.E
  725. Xwhich produces a number of diagonal stripes, each fading from black to
  726. Xwhite.
  727. XOn a 512 \*(Mu 512 image, to get the same number of stripes, use the
  728. Xtransform
  729. X.C
  730. Xnew[x,y] = x*2 + y*2
  731. X.E
  732. XA series of ripples can be produced with
  733. X.C
  734. Xnew[x,y] = (x * y) % (Z + 1)  ; page 18 (3.2)
  735. X.E
  736. Xor more simply, because all brightness values are inherently modulo
  737. X.CW "(Z + 1)"
  738. Xunless truncation is turned on
  739. X.C
  740. Xnew[x,y] = x * y
  741. X.E
  742. XA single smooth transition can be accomplished with
  743. X.C
  744. Xnew[x,y] = (Z * x * y) / ((X\-1) * (Y\-1))  ; page 18 (3.3)
  745. X.E
  746. XThe transformation
  747. X.C
  748. Xnew[x,y] = x % y
  749. X.E
  750. Xis the same as
  751. X.CW "new[x,y] = x"
  752. Xwhen
  753. X.CW "x < 0"
  754. X(ie in the lower left triangle of the image, with a different effect in
  755. Xthe upper right half.
  756. X.P
  757. XThe trig functions allow transforms such as
  758. X.C
  759. Xnew[x,y] = y + sin(x) / 2  ; page 19 (3.5)
  760. X.E
  761. Xwhich produce a series of sine waves (remember that the range of
  762. X.CW "sin(x)"
  763. Xis
  764. X.CW "\*(+-Z" .
  765. X.P
  766. XAn image reminiscent of a radar sweep can be produced by
  767. X.C
  768. Xnew[x,y] = atan(y \- Y/2, x \- X/2) * Z / 360  ; page 19 (3.6)
  769. X.E
  770. XThe
  771. X.CW atan()
  772. Xfunction has a range of 0 .. 360, so the
  773. X.CW "*Z/360"
  774. Xrescales to 0 ..
  775. X.CW Z .
  776. XThis transform is overall providing an intensity relative to the angle
  777. Xof a point in polar coordinates.
  778. XThe transform language provides the current angle as the variable
  779. X.CW a ,
  780. Xso this statement can be rewritten as
  781. X.C
  782. Xnew[x,y] = a * Z / 360
  783. X.E
  784. XPolar coordinates can be used to produce an image which varies from
  785. Xblack in the centre to white on the outside
  786. X.C
  787. Xnew[x,y] = r * Z / R  ; page 21 (3.11)
  788. X.E
  789. Xor a spiraling effect
  790. X.C
  791. Xnew[x,y] = (((a + r) % 16) \- 8) * Z / 16 + Z/2  ; page 21 (3.12)
  792. X.E
  793. XThe conditional operator can be used to provide a filled black circle
  794. X.C
  795. Xnew[x,y] = r > R/2 ? 0 : Z
  796. X.E
  797. Xor black and white patterns such as
  798. X.C
  799. Xnew[x,y] = ((x % (5 + y/25)) > 5) ? 0 : Z  ; page 20 (3.9)
  800. Xnew[x,y] = (Z * abs(x % sin(y)) > 10) ? 0 : Z  ; page 20 (3.10)
  801. X.E
  802. X.P
  803. XWe can also modify existing images using these transforms.
  804. XThe previous image can always be referred to as
  805. X.CW old ,
  806. Xor an explicitly named image can be used.
  807. XWe can read an image (eg of Dennis Ritchie) using
  808. X.C
  809. X#read "dmr"  ; read the image in the file "dmr" and name it dmr.
  810. X.E
  811. Xand then use it in a transform, such as
  812. X.C
  813. Xnew[x,y] = Z \- dmr[x,y]  ; page 22 (3.13)
  814. X.E
  815. XThis produces a negative, which can be written to a file with
  816. X.C
  817. X#write "dmr_neg"
  818. X.E
  819. Xor converted to PostScript and printed with
  820. X.C
  821. X#genps "| lp \-dalw"
  822. X.E
  823. XSince the
  824. X.CW new
  825. Ximage built during a transformation becomes the
  826. X.CW old
  827. Ximage of the following transform,
  828. Xthe negative image can be re-reversed to produce the original with
  829. X.C
  830. Xnew[x,y] = Z \- old[x,y]  ; reverse the process
  831. X.E
  832. XIn the following examples, we will use
  833. X.CW old
  834. Xin most of the transforms, rather than a particular image name.
  835. XIn practice, you would probably use a specifically named image instead.
  836. X.P
  837. XProvide a circular frame for an image
  838. X.C
  839. Xnew[x,y] = r > R/2 ? 0 : old[x,y]
  840. X.E
  841. XA solarisation process, that fades in from left to right
  842. X.C
  843. Xnew[x,y] = (old[x,y] > (Z*x) / (2 * X)) ? old[x,y] : Z\-old[x,y]  ; page 22 (3.16)
  844. X.E
  845. XGenerate a relief map
  846. X.C
  847. Xnew[x,y] = old[x,y] + (Z/2 \- old[x+2,y+2])  ; page 24 (3.19)
  848. X.E
  849. XShrink an image
  850. X.C
  851. Xnew[x,y] = old[x*2,y*2]  ; page 25 (3.24)
  852. X.E
  853. X.P
  854. XAn interesting caricature is produced by
  855. X.C
  856. Xnew[x,y] = old{sqrt(r * R),a}  ; page 34
  857. X.E
  858. XNote the use of polar coordinates.
  859. XThe reverse transform gives a fisheye lens effect:
  860. X.C
  861. Xnew[x,y] = old{(r*r)/R, a}  ; page 60
  862. X.E
  863. XThe following transform illustrates how an expression can be used for
  864. Xthe indices of the destination matrix.
  865. X.C
  866. Xnew[x, y\-old[x,y]/4] = old[x,y]  ; page 40
  867. X.E
  868. XAn image can be swirled about the centre with
  869. X.C
  870. Xnew[x,y] = old{r, a + r/3}
  871. X.E
  872. XThe following transform uses polar coordinate values in a cartesian
  873. Xreference, resulting in something that looks like what you'd see in a
  874. Xcylindrical mirror
  875. X.C
  876. Xnew[x,y] = old[a * X/A, r * Y/R]  ; page 48
  877. X.E
  878. XThe image generated by
  879. X.C
  880. Xnew[x,y] = old{ (r/16)*16, (a/16)*16 }  ; page 72
  881. X.E
  882. Xis very interesting, in that it is completely unrecognisable
  883. Xwhen viewed up close, but from a distance of a few metres it
  884. Xwill resolve into the original.
  885. X.C
  886. Xnew[x,y] = old{r, a + old{r,a)/8}  ; page 68
  887. X.E
  888. XThis image is a swirl, but with the skew dependant on the
  889. Xbrightness of the current point.
  890. X.C
  891. Xnew[x,y] = x < X/2 ? old[x,y] : old[X-x,y]
  892. Xnew[x,y] = x > X/2 ? old[x,y] : old[X-x,y]
  893. X.E
  894. XThese transformations do a horizontal mirror reversal about the
  895. Xcentre of the image.
  896. XBecause faces are usually close to, but not exactly, centered,
  897. Xthis transform of a face can be interesting.
  898. X.C
  899. Xnew[x,y] = old[x+(x%32)-16, y]  ; page 58
  900. Xnew[x,y] = old[x+((a+r/10)%32)-16, y]
  901. X.E
  902. XThese transforms applied to a face produce what looks like
  903. Xsomeone peering through a bathroom window.
  904. X.tr @@
  905. X.SH DRIVERS
  906. X.TP
  907. X.CW nulldev
  908. XThe null device driver is mainly for people with no graphics
  909. Xdisplay device for which a driver exists.
  910. XUsing this device, data for a PostScript or Epson printer can
  911. Xstill be generated.
  912. X.TP
  913. X.CW atariterm
  914. XThe atari driver is for use with "TERM", a multiplexing
  915. Xterminal program for the Atari ST, written by Peter Collinson
  916. Xof the University of Kent at Canterbury.
  917. XIt is not a driver for running native on an atari.
  918. X.TP
  919. X.CW kermit
  920. XThis is a driver for MS-Kermit 2.32 on an IBM PC, which is capable of
  921. Xemulating a Tektronix 4010. This provides three levels of contrast
  922. X(nothing, normal and bold).
  923. X.TP
  924. X.CW MGR
  925. XThis driver is for the Bell Core MGR window system. It is visually
  926. Xidentical to the SunView version, but is currently hardwired to
  927. Xmonochrome.
  928. X.TP
  929. X.CW NeWS
  930. XThis is the driver that will work with NeWS v1.1 and OpenWindows v1.0.
  931. XIt is also visually identical to the SunView version.
  932. X.TP
  933. X.CW pcturbo
  934. XThis is a driver for running popi native on a PC with
  935. XBorland's Turbo C compiler.
  936. XIt uses the graphics library supplied with Turbo C, which
  937. Xauto-detects most types of graphics display.
  938. XNo attempt at using a colourmap is done \- a single display
  939. Xdot is used for each image pixel, with simple dithering.
  940. XOnly directly accesible memory is used, which drastically
  941. Xrestricts the size of images that can be handled.
  942. X.TP
  943. X.CW SunView
  944. XThis driver is the initial version to work with the SunView
  945. Xgraphics package available on Sun Workstations.
  946. XThere is
  947. Xcurrently minimal functionality.
  948. XThe output is in 256 greyscales
  949. Xon colour machines, and an 8\*(Mu8 dither on monochrome screens.
  950. X.TP
  951. X.CW X11
  952. XA graphics implementation for use with MIT's X11 window system.
  953. XThis driver is visually identical to the SunView version.
  954. X.TP
  955. X.CW XView
  956. XA conversion of the SunView graphics driver to use the XView X11
  957. Xtoolkit. This driver is visually identical to the SunView version.
  958. X.SH SEE ALSO
  959. Xipscript(1L), imavg(1L).
  960. X.SH AUTHOR
  961. XGerald J. Holzmann, AT&T Bell Laboratories, Murray Hill, New
  962. XJersey.
  963. X.sp
  964. XModifications and additional functionality, Atari, PC, PostScript,
  965. XEpson and null drivers by
  966. XStephen Frede, Softway Pty Ltd, Australia.
  967. X.br
  968. XPopi maintainance, SunView, X11, NeWS, MGR and XView graphics drivers by
  969. XRich Burridge, Sun Microsystems, Australia.
  970. X.br
  971. XKermit graphics driver by
  972. XFrank Crawford, Q.H. Tours.
  973. X.br
  974. XAmiga graphics driver by
  975. XPeter Chubb, Softway Pty Ltd, Australia.
  976. X.br
  977. XApollo driver by
  978. XTim Lambert, University of New South Wales.
  979. X.SH BUGS
  980. XFunctions which require popen() (ie auto reading of compressed
  981. Xfiles and writing to pipes) don't work in the sequent
  982. Xmultiprocessor version.
  983. X.sp
  984. XProbably more \- please notify richb@sunaus.oz.au of any found.
  985. Funky_Stuff
  986. chmod 0444 popi.1 || echo "restore of popi.1 fails"
  987. set `wc -c popi.1`;Sum=$1
  988. if test "$Sum" != "23958"
  989. then echo original size 23958, current size $Sum;fi
  990. echo "x - extracting special.c (Text)"
  991. sed 's/^X//' << 'Funky_Stuff' > special.c &&
  992. X
  993. X/*  @(#)special.c 1.11 89/12/12
  994. X *
  995. X *  Special transformations used by the popi program.
  996. X *
  997. X *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  998. X *  This version is based on the code in his Prentice Hall book,
  999. X *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  1000. X *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  1001. X *
  1002. X *  Permission is given to distribute these extensions, as long as these
  1003. X *  introductory messages are not removed, and no monies are exchanged.
  1004. X *
  1005. X *  No responsibility is taken for any errors or inaccuracies inherent
  1006. X *  either to the comments or the code of this program, but if reported
  1007. X *  (see README file) then an attempt will be made to fix them.
  1008. X */
  1009. X
  1010. X/*      Special transformations from chapter 6 of BP.
  1011. X *
  1012. X *    The way this is done is fairly nasty at the moment,
  1013. X *        but it does work.
  1014. X */
  1015. X
  1016. X#ifndef AMIGA
  1017. X# include <sys/types.h>
  1018. X#endif /* AMIGA */
  1019. X#include <ctype.h>
  1020. X#include <time.h>
  1021. X
  1022. X#ifdef      BSD
  1023. X# include <sys/timeb.h>
  1024. X#endif   /* BSD */
  1025. X#include "popi.h"
  1026. X
  1027. X#define    GAMMA        7.5    /* default gamma for matte() */
  1028. X#define    TILESIZE    25    /* default tile size for tile() */
  1029. X#define N            3
  1030. X#define New          src[CURNEW].pix
  1031. X
  1032. X/* prototypes for local functions */
  1033. Xstruct SRC *    parseimg P((void));
  1034. Xbool        parsefname P((void));
  1035. Xvoid        oil P((void));
  1036. Xvoid        shear P((void));
  1037. Xvoid        slice P((void));
  1038. Xvoid        tile P((void));
  1039. Xvoid        melt P((void));
  1040. Xvoid        matte P((void));
  1041. Xvoid        genps P((void));
  1042. Xvoid        genepson P((void));
  1043. Xvoid        list P((void));
  1044. Xvoid        readimg P((void));
  1045. Xvoid        writeimg P((void));
  1046. Xvoid        freeimg P((void));
  1047. Xvoid        displayimg P((void));
  1048. Xvoid        CloseLog P((void));
  1049. Xvoid        dolog P((void));
  1050. Xvoid        debug P((void));
  1051. Xvoid        undo P((void));
  1052. Xvoid        verbose P((void));
  1053. Xvoid        trunc P((void));
  1054. X
  1055. X/*
  1056. X * convenience function, since most of these routines have
  1057. X * an image as their 1st parameter.
  1058. X */
  1059. Xstatic struct SRC *
  1060. Xparseimg()
  1061. X{
  1062. X    lex();
  1063. X
  1064. X    if (lat == '\n' || lat == ')')
  1065. X    {
  1066. X    pushback(lat);
  1067. X    return &src[CUROLD];
  1068. X    }
  1069. X
  1070. X    if (lat != INAME)
  1071. X    {
  1072. X    SPRINTF(ErrBuf, "Expected image name");
  1073. X    error(ERR_PARSE);
  1074. X    return (struct SRC *) 0;
  1075. X    }
  1076. X
  1077. X    return &src[lexval + 1];
  1078. X}
  1079. X
  1080. Xstatic bool
  1081. Xparsefname()
  1082. X{
  1083. X    lex();
  1084. X
  1085. X    if (lat == '\n')
  1086. X    pushback(lat);
  1087. X
  1088. X    if (lat != FNAME)
  1089. X    {
  1090. X    SPRINTF(ErrBuf, "Expected file name");
  1091. X    error(ERR_PARSE);
  1092. X    return FALSE;
  1093. X    }
  1094. X    return TRUE;
  1095. X}
  1096. X
  1097. Xstatic void
  1098. Xoil()
  1099. X{
  1100. X    register int    x, y;
  1101. X    register int    dx, dy;
  1102. X    pixel_t        mfp;
  1103. X    static int        *histo = 0;
  1104. X    struct SRC          *srcp;
  1105. X    pixel_t        **img;
  1106. X
  1107. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1108. X    return;
  1109. X    img = srcp->pix;
  1110. X
  1111. X    if
  1112. X    (
  1113. X    histo == (int *) 0
  1114. X    &&
  1115. X    (histo = (int *) LINT_CAST(Emalloc((unsigned)Zsize * sizeof (int)))) == (int *) 0
  1116. X    )
  1117. X    return;
  1118. X
  1119. X    if (disp_active)
  1120. X    disp_imgstart();
  1121. X
  1122. X    for (y = N; y < Ysize-N; y++)
  1123. X    {
  1124. X        for (x = N; x < Xsize-N; x++)
  1125. X    {
  1126. X        for (dx = 0; dx < Zsize; dx++)
  1127. X        histo[dx] = 0;
  1128. X        for (dy = y-N; dy <= y+N; dy++)
  1129. X        for (dx = x-N; dx <= x+N; dx++)
  1130. X            histo[img[dy][dx]]++;
  1131. X        for (dx = dy = 0; dx < Zsize; dx++)
  1132. X        if (histo[dx] > dy)
  1133. X            {
  1134. X            dy = histo[dx];
  1135. X            mfp = (pixel_t) dx;
  1136. X            }
  1137. X        New[y][x] = mfp;
  1138. X    }
  1139. X
  1140. X    if (disp_active)
  1141. X        disp_putline(New[y], y);
  1142. X    disp_percentdone(y * 100 / (Ysize-1));
  1143. X    }
  1144. X
  1145. X    if (disp_active)
  1146. X    disp_imgend();
  1147. X
  1148. X    SwapOldNew();
  1149. X}
  1150. X
  1151. X
  1152. Xstatic void
  1153. Xshear()
  1154. X{
  1155. X    register int    x, y, r;
  1156. X    int            dx, dy;
  1157. X    static int        *yshift = 0;
  1158. X    struct SRC          *srcp;
  1159. X    pixel_t        **img;
  1160. X
  1161. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1162. X    return;
  1163. X
  1164. X    img = srcp->pix;
  1165. X
  1166. X    if
  1167. X    (
  1168. X    yshift == 0
  1169. X    &&
  1170. X    (yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof(int)))) == 0
  1171. X    )
  1172. X    return;
  1173. X
  1174. X    if (disp_active)
  1175. X    disp_imgstart();
  1176. X
  1177. X    for (x = r = 0; x < Xsize; x++)
  1178. X    {
  1179. X    if (RANDOM % Zsize < 128)
  1180. X        r--;
  1181. X    else
  1182. X        r++;
  1183. X    yshift[x] = r;
  1184. X    }
  1185. X
  1186. X    for (y = 0; y < Ysize; y++)
  1187. X    {
  1188. X    if (RANDOM % Zsize < 128)
  1189. X        r--;
  1190. X    else
  1191. X        r++;
  1192. X
  1193. X    for (x = 0; x < Xsize; x++)
  1194. X    {
  1195. X        dx = x + r;
  1196. X        dy = y + yshift[x];
  1197. X        if (dx >= Xsize || dy >= Ysize || dx < 0 || dy < 0)
  1198. X        continue;
  1199. X        New[y][x] = img[dy][dx];
  1200. X    }
  1201. X
  1202. X    if (disp_active)
  1203. X        disp_putline(New[y], y);
  1204. X    disp_percentdone(y * 100 / (Ysize-1));
  1205. X    }
  1206. X
  1207. X    if (disp_active)
  1208. X    disp_imgend();
  1209. X
  1210. X    SwapOldNew();
  1211. X}
  1212. X
  1213. X
  1214. Xstatic void
  1215. Xslice()
  1216. X{
  1217. X    register int    x, y, r;
  1218. X    int            dx, dy;
  1219. X    struct SRC          *srcp;
  1220. X    pixel_t        **img;
  1221. X    static int        *xshift = 0,
  1222. X            *yshift = 0;
  1223. X
  1224. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1225. X    return;
  1226. X    img = srcp->pix;
  1227. X
  1228. X    if
  1229. X    (
  1230. X    xshift == 0
  1231. X    &&
  1232. X    (xshift = (int *) LINT_CAST(Emalloc((unsigned)Ysize * sizeof (int)))) == 0
  1233. X    )
  1234. X    return;
  1235. X    if
  1236. X    (
  1237. X    yshift == 0
  1238. X    &&
  1239. X    (yshift = (int *) LINT_CAST(Emalloc((unsigned)Xsize * sizeof (int)))) == 0
  1240. X    )
  1241. X    return;
  1242. X
  1243. X    if (disp_active)
  1244. X    disp_imgstart();
  1245. X
  1246. X    for (x = dx = 0 ; x < Xsize; x++)
  1247. X    {
  1248. X        if (dx == 0)
  1249. X        {
  1250. X            r = (RANDOM & 63) - 32;
  1251. X            dx = 8 + RANDOM & 31;
  1252. X        }
  1253. X        else
  1254. X        dx--;
  1255. X        yshift[x] = r;
  1256. X    }
  1257. X    for (y = dy = 0; y < Ysize; y++)
  1258. X    {
  1259. X        if (dy == 0)
  1260. X        {
  1261. X            r = (RANDOM & 63) - 32;
  1262. X            dy = 8 + RANDOM & 31;
  1263. X        }
  1264. X        else
  1265. X        dy--;
  1266. X        xshift[y] = r;
  1267. X    }
  1268. X
  1269. X    for (y = 0; y < Ysize; y++)
  1270. X    {
  1271. X        for (x = 0; x < Xsize; x++)
  1272. X        {
  1273. X            dx = x + xshift[y];
  1274. X            dy = y + yshift[x];
  1275. X            if (dx < Xsize && dy < Ysize && dx >= 0 && dy >= 0)
  1276. X                New[y][x] = img[dy][dx];
  1277. X        }
  1278. X
  1279. X    if (disp_active)
  1280. X        disp_putline(New[y], y);
  1281. X    disp_percentdone(y * 100 / (Ysize-1));
  1282. X    }
  1283. X
  1284. X    if (disp_active)
  1285. X    disp_imgend();
  1286. X
  1287. X    SwapOldNew();
  1288. X}
  1289. X
  1290. X
  1291. Xstatic void
  1292. Xtile()
  1293. X{
  1294. X    register int    x,
  1295. X            y,
  1296. X            dx,
  1297. X            dy;
  1298. X    int            ox,
  1299. X            oy,
  1300. X            nx,
  1301. X            ny,
  1302. X            TileSize = TILESIZE;
  1303. X    struct SRC          *srcp;
  1304. X    pixel_t        **img;
  1305. X
  1306. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1307. X    return;
  1308. X    img = srcp->pix;
  1309. X
  1310. X    for (y = 0; y < Ysize-TileSize; y += TileSize)
  1311. X    {
  1312. X    for (x = 0; x < Xsize-TileSize; x += TileSize)
  1313. X        {
  1314. X        ox = (RANDOM & 31) - 16 ;       /* Displacement. */
  1315. X        oy = (RANDOM & 31) - 16;
  1316. X
  1317. X        for (dy = y; dy < y+TileSize; dy++)
  1318. X            for (dx = x; dx < x+TileSize; dx++)
  1319. X            {
  1320. X                nx = dx + ox;
  1321. X                ny = dy + oy;
  1322. X                if (nx >= Xsize || ny >= Ysize || nx < 0 || ny < 0)
  1323. X            continue;
  1324. X                New[ny][nx] = img[dy][dx];
  1325. X        }
  1326. X        }
  1327. X    disp_percentdone(y * 100 / (Ysize-1));
  1328. X    }
  1329. X
  1330. X    if (disp_active)
  1331. X    {
  1332. X    disp_imgstart();
  1333. X    for (y = 0; y < Ysize; y++)
  1334. X        disp_putline(New[y], y);
  1335. X    disp_imgend();
  1336. X    }
  1337. X
  1338. X    SwapOldNew();
  1339. X}
  1340. X
  1341. X
  1342. X/*
  1343. X *    Note: affects source image in situ.
  1344. X *    Buffers not swapped after processing.
  1345. X */
  1346. Xstatic void
  1347. Xmelt()
  1348. X{
  1349. X    register int    x,
  1350. X            y,
  1351. X            k,
  1352. X            NumPixels;
  1353. X    pixel_t        val;
  1354. X    struct SRC          *srcp;
  1355. X    pixel_t        **img;
  1356. X
  1357. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1358. X    return;
  1359. X    img = srcp->pix;
  1360. X
  1361. X    NumPixels = Xsize * Ysize;
  1362. X    for (k = 0; k < NumPixels; k++)
  1363. X    {
  1364. X        x = RANDOM % Xsize;
  1365. X        y = RANDOM % (Ysize - 1);
  1366. X
  1367. X        while (y < Ysize-1 && img[y][x] <= img[y+1][x])
  1368. X    {
  1369. X        val = img[y][x];
  1370. X        img[y][x] = img[y+1][x];
  1371. X        img[y+1][x] = val;
  1372. X        y++;
  1373. X    }
  1374. X    disp_percentdone(k * 100 / (NumPixels-1));
  1375. X    }
  1376. X    if (disp_active)
  1377. X    {
  1378. X    disp_imgstart();
  1379. X    for (y = 0; y < Ysize; y++)
  1380. X        disp_putline(img[y], y);
  1381. X    disp_imgend();
  1382. X    }
  1383. X}
  1384. X
  1385. X
  1386. Xstatic void
  1387. Xmatte()
  1388. X{
  1389. X    struct SRC          *srcp;
  1390. X    pixel_t        **img;
  1391. X    double        gamma;
  1392. X    register        x,
  1393. X            y;
  1394. X    static pixel_t    *lookup = (pixel_t *) 0;
  1395. X    static double    lastgamma = 0.0;
  1396. X
  1397. X    DEBUG((Debug, "matte()\n"));
  1398. X
  1399. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1400. X    return;
  1401. X    img = srcp->pix;
  1402. X
  1403. X    lex();
  1404. X    if (lat == '\n' || lat == ')')
  1405. X    {
  1406. X    gamma = GAMMA;
  1407. X    pushback(lat);
  1408. X    }
  1409. X    else
  1410. X    gamma = lexval + lexfract;
  1411. X
  1412. X    if
  1413. X    (
  1414. X    lookup == 0
  1415. X    &&
  1416. X    (lookup = (pixel_t *) Emalloc((unsigned)Zsize)) == (pixel_t *) 0
  1417. X    )
  1418. X    return;
  1419. X
  1420. X    if (lastgamma != gamma)
  1421. X    {
  1422. X    for (x = 0; x < Zsize; ++x)
  1423. X        lookup[x] = ((double)Zmax * pow(x / (double)Zmax, gamma) < 3.0)
  1424. X            ? Zmax : 0;
  1425. X    lastgamma = gamma;
  1426. X    }
  1427. X
  1428. X    if (disp_active)
  1429. X    disp_imgstart();
  1430. X    for (y = 0; y < Ysize; y++)
  1431. X    {
  1432. X    for (x = 0; x < Xsize; x++)
  1433. X        New[y][x] = lookup[img[y][x]];
  1434. X    if (disp_active)
  1435. X        disp_putline(New[y], y);
  1436. X    disp_percentdone(y * 100 / (Ysize-1));
  1437. X    }
  1438. X    if (disp_active)
  1439. X    disp_imgend();
  1440. X}
  1441. X
  1442. Xstatic void
  1443. Xgenps()
  1444. X{
  1445. X    int            x,
  1446. X            y;
  1447. X    FILE        *ostr;
  1448. X    struct SRC        *srcp;
  1449. X    pixel_t        **img,
  1450. X            *ip;
  1451. X    time_t        time P((time_t *)),
  1452. X            clock;
  1453. X#if unix
  1454. X    char        *getlogin P((void));
  1455. X#endif /* unix */
  1456. X
  1457. X    if (!parsefname())
  1458. X    return;
  1459. X
  1460. X    if ((ostr = EfopenW(text)) == NULL)
  1461. X    return;
  1462. X
  1463. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1464. X    return;
  1465. X
  1466. X    img = srcp->pix;
  1467. X    clock = time((time_t *) 0);
  1468. X    
  1469. X    FPRINTF(ostr, "%%!PS-Adobe-1.0\n");
  1470. X    FPRINTF(ostr, "%%%%Title: popi bit image '%s'\n", srcp->str);
  1471. X    FPRINTF(ostr, "%%%%DocumentFonts:\n");
  1472. X    FPRINTF(ostr, "%%%%Creator: popi\n");
  1473. X    FPRINTF(ostr, "%%%%CreationDate: %s", ctime(&clock)); /* includes \n */
  1474. X    FPRINTF(ostr, "%%%%Pages: 1\n");
  1475. X#if    unix
  1476. X    FPRINTF(ostr, "%%%%For: %s\n", getlogin());
  1477. X#endif    /* unix */
  1478. X    FPRINTF(ostr, "%%%%EndComments\n");
  1479. X    FPRINTF(ostr, "clippath pathbbox pop pop translate\n");
  1480. X    FPRINTF(ostr, "clippath pathbbox pop exch pop exch sub dup scale\n");
  1481. X    FPRINTF(ostr, "/picstr %d string def\n", Xsize);
  1482. X    FPRINTF(ostr, "/doimage {\n");
  1483. X    FPRINTF(ostr, "%d %d %d [ %d 0 0 -%d 0 %d ]\n",
  1484. X    Xsize, Ysize, BITSPERPIXEL, Xsize, Ysize, Ysize);
  1485. X    FPRINTF(ostr, "{currentfile picstr readhexstring pop}image}bind def\n");
  1486. X    FPRINTF(ostr, "%%%%EndProlog\n%%%%Page 0 0\ndoimage\n");
  1487. X
  1488. X    for(y = 0; y < Ysize; ++y)
  1489. X    {
  1490. X    ip = &img[y][0];
  1491. X    for(x = 0; x < Xsize; ++x)
  1492. X    {
  1493. X        if (x % 40 == 0)        /* formatting only */
  1494. X        PUTC('\n', ostr);
  1495. X        FPRINTF(ostr, "%02x", *ip++);
  1496. X    }
  1497. X    PUTC('\n', ostr);
  1498. X    }
  1499. X
  1500. X    FPRINTF(ostr, "showpage\n");
  1501. X    Efclose(ostr);
  1502. X}
  1503. X
  1504. X/*
  1505. X * Although this is set up to use one particular graphics mode
  1506. X * of a 24-pin printer, everything should be generic enough
  1507. X * that it can be changed to work with a different graphics
  1508. X * mode on an 8-pin printer, just by changing a few numbers.
  1509. X */
  1510. Xstatic void
  1511. Xgenepson()
  1512. X{
  1513. X    struct SRC        *srcp;
  1514. X    char        *PinVals;
  1515. X    pixel_t        *PinThresh,
  1516. X            ThreshStep;
  1517. X    FILE        *ostr;
  1518. X    register int    x;
  1519. X    register pixel_t    **img;
  1520. X    int            y,
  1521. X            yn;
  1522. X    int            pin;
  1523. X    int            BytesPerChunk,
  1524. X            PinsPerPixel,
  1525. X            BytesPerColumn,
  1526. X            yPixelsPerByte,
  1527. X            xPinsPerPixel,
  1528. X            yPinsPerPixel;
  1529. X
  1530. X    if (parsefname() ==    0)
  1531. X    return;
  1532. X
  1533. X    if ((ostr =    EfopenW(text)) == NULL)
  1534. X    return;
  1535. X
  1536. X    if ((srcp =    parseimg()) == (struct SRC *) 0)
  1537. X    return;
  1538. X
  1539. X    img    = srcp->pix;
  1540. X
  1541. X    /* printer specific    */
  1542. X    xPinsPerPixel = 4;
  1543. X    yPinsPerPixel = 4;
  1544. X    BytesPerColumn = 24    / BITSINBYTE;
  1545. X
  1546. X    PinsPerPixel = xPinsPerPixel * yPinsPerPixel;
  1547. X    BytesPerChunk = xPinsPerPixel * BytesPerColumn;
  1548. X    yPixelsPerByte = BITSINBYTE    / yPinsPerPixel;
  1549. X
  1550. X    /* Must be whole number of pixels (y direction) per    byte. */
  1551. X    assert(yPinsPerPixel * yPixelsPerByte == BITSINBYTE);
  1552. X
  1553. X    /* Reallocate these    each time, as changing the print mode
  1554. X     * may change the sizes of these arrays.
  1555. X     */
  1556. X    if
  1557. X    (
  1558. X    (PinVals = Emalloc((unsigned)BytesPerChunk)) ==    0
  1559. X    ||
  1560. X    (PinThresh = (pixel_t *) Emalloc((unsigned)PinsPerPixel * sizeof(pixel_t))) == 0
  1561. X    )
  1562. X    return;
  1563. X
  1564. X    ThreshStep = (pixel_t) (Zsize / (PinsPerPixel + 1));
  1565. X    for    (pin = 0; pin <    PinsPerPixel; ++pin)
  1566. X    PinThresh[pin] = (pixel_t) ((pin + 1) * ThreshStep);
  1567. X
  1568. X    for    (y = 0;    y < Ysize; y = yn)
  1569. X    {
  1570. X
  1571. X    /* printer specific */
  1572. X    /*
  1573. X     * This    print line is width Xsize pixels, and (Xsize * xPinsPerPixel)
  1574. X     * pin positions (dots on the page).
  1575. X     * No. of dots vertical    is (BytesPerColumn * BITSINBYTE)
  1576. X     * which is yPinsPerPixel times    the no.    of image scanlines.
  1577. X     */
  1578. X    FPRINTF(ostr,
  1579. X        "\033*%c%c%c",
  1580. X        39,        /* 180 dpi in both directions */
  1581. X        (Xsize * xPinsPerPixel) % 256,
  1582. X        (Xsize * xPinsPerPixel) / 256
  1583. X        );
  1584. X
  1585. X    for (x = 0; x <    Xsize; ++x)
  1586. X    {
  1587. X        register int    ycur;
  1588. X        int            ByteCount,
  1589. X                xpin;
  1590. X        char        *dp;
  1591. X
  1592. X        /* Clear the PinVals array */
  1593. X        for
  1594. X        (
  1595. X        ByteCount = 0, dp = PinVals;
  1596. X        ByteCount < BytesPerChunk;
  1597. X        ++ByteCount
  1598. X        )
  1599. X        *dp++ =    0;
  1600. X
  1601. X        dp = PinVals;
  1602. X
  1603. X        /* For each    byte-sized row of the print head,
  1604. X         * collect 1 pixel width of    data.
  1605. X         */
  1606. X        for
  1607. X        (
  1608. X        ByteCount = 0, dp = PinVals, ycur = y;
  1609. X        ByteCount < BytesPerColumn;
  1610. X        ++ByteCount, dp    += xPinsPerPixel
  1611. X        )
  1612. X        {
  1613. X        register unsigned char    bit;
  1614. X
  1615. X        yn = ycur + yPixelsPerByte;
  1616. X        if (yn > Ysize)
  1617. X            yn = Ysize;
  1618. X
  1619. X        /* For the current byte    row of the print-head
  1620. X         * (ie yPixelsPerByte image scanlines),
  1621. X         * collect a pixel width of data.
  1622. X         */
  1623. X        for (bit = 0x80; ycur <    yn; ++ycur)
  1624. X        {
  1625. X            pixel_t            val;
  1626. X            int                ypin;
  1627. X
  1628. X            val    = img[ycur][x];
  1629. X
  1630. X            /* Now use an appropriate no. of pins to simulate
  1631. X             * the greyscale value.
  1632. X             */
  1633. X            for
  1634. X            (
  1635. X            ypin = 0, pin =    0;
  1636. X            ypin < yPinsPerPixel;
  1637. X            ++ypin
  1638. X            )
  1639. X            {
  1640. X            for (xpin = 0; xpin < xPinsPerPixel; ++xpin, ++pin)
  1641. X            {
  1642. X                if (val < PinThresh[pin])
  1643. X                dp[xpin] |= bit;
  1644. X            }
  1645. X            /* xpin    == xPinsPerPixel */
  1646. X            bit >>=    1;
  1647. X            }
  1648. X            /* ypin == YpinsPerPixel */
  1649. X        }
  1650. X        /* ycur    == y */
  1651. X        }
  1652. X        /* ByteCount == BytesPerColumn */
  1653. X
  1654. X        /* We have set up enough columns for a single pixel    in
  1655. X         * the x direction.    Now print them in the correct order.
  1656. X         */
  1657. X        for    (xpin =    0; xpin    < xPinsPerPixel; ++xpin)
  1658. X        {
  1659. X        for (ByteCount = 0; ByteCount <    BytesPerColumn;    ++ByteCount)
  1660. X        {
  1661. X            PUTC(PinVals[ByteCount * xPinsPerPixel + xpin], ostr);
  1662. X        }
  1663. X        }
  1664. X        /* xpin == xPinsPerPixel */
  1665. X    }
  1666. X    /* x ==    Xsize */
  1667. X
  1668. X    /* Printer specific */
  1669. X    FPRINTF(ostr, "\033J%c\r", 24);
  1670. X    }
  1671. X    /* y == Ysize */
  1672. X
  1673. X    Efclose(ostr);
  1674. X    free(PinVals);
  1675. X    free((char *) PinThresh);
  1676. X}
  1677. X
  1678. Xstatic void
  1679. Xlist()
  1680. X{
  1681. X    showfiles();
  1682. X}
  1683. X
  1684. X/*
  1685. X *    #read "filename" [imagename]
  1686. X */
  1687. Xstatic void
  1688. Xreadimg()
  1689. X{
  1690. X    char    filename[512],
  1691. X        *imgname = (char *) 0;
  1692. X
  1693. X    if (parsefname() == 0)
  1694. X    return;
  1695. X    
  1696. X    STRCPY(filename, text);
  1697. X
  1698. X    lex();
  1699. X
  1700. X    if (lat == '\n' || lat == ')')
  1701. X    {
  1702. X    pushback(lat);
  1703. X    }
  1704. X    else if (lat != NAME && lat != INAME)
  1705. X    {
  1706. X    SPRINTF(ErrBuf, "Expected image name");
  1707. X    error(ERR_PARSE);
  1708. X    }
  1709. X    else
  1710. X    imgname = text;
  1711. X
  1712. X    getpix(filename, imgname);
  1713. X}
  1714. X
  1715. Xstatic void
  1716. Xwriteimg()
  1717. X{
  1718. X    struct SRC    *srcp;
  1719. X
  1720. X    if (parsefname() == 0)
  1721. X    return;
  1722. X
  1723. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1724. X    return;
  1725. X
  1726. X    putpix(srcp, text);
  1727. X}
  1728. X
  1729. Xstatic void
  1730. Xfreeimg()
  1731. X{
  1732. X    struct SRC    *srcp;
  1733. X
  1734. X    if ((srcp = parseimg()) == (struct SRC *) 0)
  1735. X    return;
  1736. X    
  1737. X    if (srcp == &src[CUROLD] || srcp == &src[CURNEW])
  1738. X    {
  1739. X    SPRINTF(ErrBuf, "Cannot free 'old' or 'new'");
  1740. X    error(0);
  1741. X    return;
  1742. X    }
  1743. X
  1744. X    ImgFree(srcp);
  1745. X}
  1746. X
  1747. Xstatic void
  1748. Xdisplayimg()
  1749. X{
  1750. X    pixel_t        **img;
  1751. X    int            y;
  1752. X
  1753. X
  1754. X    lex();
  1755. X
  1756. X    if (lat == '+')
  1757. X    {
  1758. X    disp_active = 1;
  1759. X    return;
  1760. X    }
  1761. X    if (lat == '-')
  1762. X    {
  1763. X    disp_active = 0;
  1764. X    return;
  1765. X    }
  1766. X    if (lat == '\n')
  1767. X    {
  1768. X    pushback(lat);
  1769. X    img = src[CUROLD].pix;
  1770. X    }
  1771. X    else if (lat == INAME)
  1772. X    img = src[lexval + 1].pix;
  1773. X    else if (lat == NEW)
  1774. X    img = src[CURNEW].pix;
  1775. X    else
  1776. X    {
  1777. X    SPRINTF(ErrBuf, "Expected +, - or image name");
  1778. X    error(ERR_PARSE);
  1779. X    return;
  1780. X    }
  1781. X
  1782. X    disp_imgstart();
  1783. X
  1784. X    for (y = 0; y < Ysize; y++)
  1785. X    disp_putline(img[y], y);
  1786. X
  1787. X    disp_imgend();
  1788. X}
  1789. X
  1790. Xstatic void
  1791. XCloseLog()
  1792. X{
  1793. X    if (LogStr == NULL)
  1794. X    return;
  1795. X
  1796. X    FPRINTF(LogStr, "\n---\n");
  1797. X    FCLOSE(LogStr);
  1798. X    LogStr = NULL;
  1799. X}
  1800. X
  1801. Xvoid
  1802. XOpenLog()
  1803. X{
  1804. X    time_t        time(),
  1805. X            clock;
  1806. X
  1807. X    CloseLog();
  1808. X
  1809. X    if ((LogStr = fopen(LogFile, "a")) == NULL)
  1810. X    {
  1811. X    SPRINTF(ErrBuf,
  1812. X        "Can't open log file '%s' - logging is off",
  1813. X        LogFile);
  1814. X    error(ERR_SYS);
  1815. X    return;
  1816. X    }
  1817. X
  1818. X    clock = time((time_t *) 0);
  1819. X    FPRINTF(LogStr, "==>> %s", ctime(&clock)); /* includes '\n' */
  1820. X}
  1821. X
  1822. Xstatic void
  1823. Xdolog()
  1824. X{
  1825. X    static char    *buf = (char *) 0;
  1826. X
  1827. X    lex();
  1828. X
  1829. X    if (lat == '+')
  1830. X    OpenLog();
  1831. X    else if (lat == '-')
  1832. X    CloseLog();
  1833. X    else if (lat == FNAME)
  1834. X    {
  1835. X    if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
  1836. X        return;
  1837. X    STRCPY(buf, text);
  1838. X    LogFile = buf;
  1839. X    OpenLog();
  1840. X    }
  1841. X    else
  1842. X    pushback(lat);
  1843. X    
  1844. X    if (LogStr)
  1845. X    PRINTF("Logging is active on file '%s'\n", LogFile);
  1846. X    else
  1847. X    PRINTF("Logging is off\n");
  1848. X}
  1849. X
  1850. Xstatic void
  1851. Xdebug()
  1852. X{
  1853. X    static char    *buf = (char *) 0;
  1854. X
  1855. X    lex();
  1856. X
  1857. X    if (lat == '+')
  1858. X    OpenLog();
  1859. X    else if (lat == '-')
  1860. X    CloseLog();
  1861. X    else if (lat == FNAME)
  1862. X    {
  1863. X    if (buf == (char *) 0 && (buf = Emalloc((unsigned int) 512)) == (char *) 0)
  1864. X        return;
  1865. X    STRCPY(buf, text);
  1866. X    LogFile = buf;
  1867. X    OpenLog();
  1868. X    }
  1869. X    else
  1870. X    pushback(lat);
  1871. X    
  1872. X    if (LogStr)
  1873. X    PRINTF("Logging is active on file '%s'\n", LogFile);
  1874. X    else
  1875. X    PRINTF("Logging is off\n");
  1876. X}
  1877. X
  1878. Xstatic char *HelpMsg[] =
  1879. X{
  1880. X    "binary ops: ** * /  % + - << >> < > >= <= == != & ^ | && ||",
  1881. X    "funcs: sin(deg) cos(deg) atan(y, x) log(val) sqrt(val) abs(val) rand()",
  1882. X    "values: x y r a X Y R A Z",
  1883. X    "special funcs",
  1884. X    "\t#read \"filename\"",
  1885. X    "\t#write \"filename\"",
  1886. X    "\t#genps \"filename\" [image]",
  1887. X    "\t#display [image]",
  1888. X    "\t#display +",
  1889. X    "\t#display -",
  1890. X    (char *) 0
  1891. X};
  1892. X
  1893. Xvoid
  1894. Xhelp()
  1895. X{
  1896. X    PrStrs(HelpMsg);
  1897. X}
  1898. X
  1899. Xstatic void
  1900. Xundo()
  1901. X{
  1902. X    SwapOldNew();
  1903. X}
  1904. X
  1905. Xstatic void
  1906. Xverbose()
  1907. X{
  1908. X    lex();
  1909. X
  1910. X    if (lat == '+')
  1911. X    Verbose = 1;
  1912. X    else if (lat == '-')
  1913. X    Verbose = 0;
  1914. X    else
  1915. X    pushback(lat);
  1916. X    
  1917. X    PRINTF("Verbose is %s\n", Verbose ? "on" : "off");
  1918. X}
  1919. X
  1920. Xstatic void
  1921. Xtrunc()
  1922. X{
  1923. X    lex();
  1924. X
  1925. X    if (lat == '+')
  1926. X    Truncate = 1;
  1927. X    else if (lat == '-')
  1928. X    Truncate = 0;
  1929. X    else
  1930. X    pushback(lat);
  1931. X    
  1932. X    PRINTF("Truncation is %s\n", Truncate ? "on" : "off");
  1933. X}
  1934. X
  1935. Xstruct SpecialOp
  1936. X{
  1937. X    char    *name;
  1938. X    void    (*func) P((void));
  1939. X};
  1940. X
  1941. Xstatic struct SpecialOp SpecialOps[] =
  1942. X{
  1943. X    { "matte",        matte },
  1944. X    { "oil",        oil },
  1945. X    { "slice",        slice },
  1946. X    { "shear",        shear },
  1947. X    { "tile",        tile },
  1948. X    { "melt",        melt },
  1949. X    { "read",        readimg },
  1950. Funky_Stuff
  1951. echo "End of part 4"
  1952. echo "File special.c is continued in part 5"
  1953. echo "5" > s2_seq_.tmp
  1954. exit 0
  1955.  
  1956.