aboutsummaryrefslogtreecommitdiff
path: root/pkg/images/tv/iis/src
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/images/tv/iis/src
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/images/tv/iis/src')
-rw-r--r--pkg/images/tv/iis/src/blink.x132
-rw-r--r--pkg/images/tv/iis/src/clear.x48
-rw-r--r--pkg/images/tv/iis/src/cv.com16
-rw-r--r--pkg/images/tv/iis/src/cv.h51
-rw-r--r--pkg/images/tv/iis/src/cv.x175
-rw-r--r--pkg/images/tv/iis/src/cvparse.x196
-rw-r--r--pkg/images/tv/iis/src/cvulut.x130
-rw-r--r--pkg/images/tv/iis/src/cvutil.x538
-rw-r--r--pkg/images/tv/iis/src/display.x104
-rw-r--r--pkg/images/tv/iis/src/gwindow.h34
-rw-r--r--pkg/images/tv/iis/src/load1.x324
-rw-r--r--pkg/images/tv/iis/src/load2.x335
-rw-r--r--pkg/images/tv/iis/src/map.x320
-rw-r--r--pkg/images/tv/iis/src/match.x172
-rw-r--r--pkg/images/tv/iis/src/maxmin.x52
-rw-r--r--pkg/images/tv/iis/src/mkpkg39
-rw-r--r--pkg/images/tv/iis/src/offset.x53
-rw-r--r--pkg/images/tv/iis/src/pan.x99
-rw-r--r--pkg/images/tv/iis/src/range.x57
-rw-r--r--pkg/images/tv/iis/src/rdcur.x111
-rw-r--r--pkg/images/tv/iis/src/reset.x37
-rw-r--r--pkg/images/tv/iis/src/sigl2.x677
-rw-r--r--pkg/images/tv/iis/src/snap.x64
-rw-r--r--pkg/images/tv/iis/src/split.x95
-rw-r--r--pkg/images/tv/iis/src/tell.x24
-rw-r--r--pkg/images/tv/iis/src/text.x71
-rw-r--r--pkg/images/tv/iis/src/window.x181
-rw-r--r--pkg/images/tv/iis/src/zoom.x60
-rw-r--r--pkg/images/tv/iis/src/zscale.x457
29 files changed, 4652 insertions, 0 deletions
diff --git a/pkg/images/tv/iis/src/blink.x b/pkg/images/tv/iis/src/blink.x
new file mode 100644
index 00000000..fc176f7a
--- /dev/null
+++ b/pkg/images/tv/iis/src/blink.x
@@ -0,0 +1,132 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# BLINK -- blink the display.
+
+procedure blink()
+
+char token[SZ_LINE]
+int tok, count, rate
+int sets, button, i
+int ctoi(), ip
+pointer sp, setp, ptr
+int cv_rdbut()
+int val, nchar
+
+define errmsg 10
+
+include "cv.com"
+
+begin
+ # get rate for blink
+
+ call gargtok (tok, token, SZ_LINE)
+ if (tok != TOK_NUMBER) {
+ call eprintf ("Bad blink rate: %s\n")
+ call pargstr (token)
+ return
+ }
+ ip = 1
+ count = ctoi(token, ip, rate)
+ if (rate < 0) {
+ call eprintf ("negative rate not legal\n")
+ return
+ }
+
+ call smark (sp)
+ # The "3" is to hold frame/color/quad for one frame;
+ # the "2" is to allow duplication of each frame so that
+ # some frames can stay "on" longer. The extra "1" is for graphics.
+ call salloc (setp, 2 * 3 * (cv_maxframes+1), TY_POINTER)
+ sets = 0
+
+ # which frames to blink
+
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ while ( (sets <= cv_maxframes+1) && (tok != TOK_NEWLINE) ) {
+ sets = sets + 1
+ ptr = setp + (3 * (sets-1))
+ call salloc (Memi[ptr], IDS_MAXIMPL+1, TY_SHORT)
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'f') {
+ call cv_frame (token[2], Mems[Memi[ptr]])
+ if (Mems[Memi[ptr]] == ERR) {
+ call sfree (sp)
+ return
+ }
+ }
+ } else if (tok == TOK_NUMBER) {
+ ip = 1
+ nchar = ctoi (token[1], ip, val)
+ if ( (val < 0) || (val > cv_maxframes)) {
+ call eprintf ("illegal frame value: %s\n")
+ call pargstr (token)
+ call sfree (sp)
+ return
+ }
+ Mems[Memi[ptr]] = val
+ Mems[Memi[ptr]+1] = IDS_EOD
+ } else {
+errmsg
+ call eprintf ("Unexpected input: %s\n")
+ call pargstr (token)
+ call sfree (sp)
+ return
+ }
+ ptr = ptr + 1
+ call salloc (Memi[ptr], IDS_MAXGCOLOR+1, TY_SHORT)
+ call salloc (Memi[ptr+1], 5, TY_SHORT)
+ Mems[Memi[ptr]] = IDS_EOD # default all colors
+ Mems[Memi[ptr+1]] = IDS_EOD # default all quads
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if ( (tok != TOK_IDENTIFIER) && (tok != TOK_NEWLINE))
+ goto errmsg
+ if ((tok == TOK_IDENTIFIER) && (token[1] == 'c')) {
+ call cv_color (token[2], Mems[Memi[ptr]])
+ if (Mems[Memi[ptr]] == ERR) {
+ call sfree (sp)
+ return
+ }
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+ if ( (tok != TOK_IDENTIFIER) && (tok != TOK_NEWLINE))
+ goto errmsg
+ if ((tok == TOK_IDENTIFIER) && (token[1] == 'q')) {
+ call cv_quad (token[2], Mems[Memi[ptr+1]])
+ if (Mems[Memi[ptr+1]] == ERR) {
+ call sfree (sp)
+ return
+ }
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+ } # end while
+
+ button = cv_rdbut() # clear any buttons pressed
+ call eprintf ("Press any button to terminate blink\n")
+ repeat {
+ do i = 1, sets {
+ ptr = setp + 3 * (i-1)
+ call cvdisplay (IDS_ON, IDS_DISPLAY_I, Mems[Memi[ptr]],
+ Mems[Memi[ptr+1]], Mems[Memi[ptr+2]])
+ # Delay for "rate*100" milliseconds
+ call zwmsec (rate * 100)
+
+ # Leave something on screen when button pushed
+ button = cv_rdbut()
+ if (button > 0)
+ break
+ call cvdisplay (IDS_OFF, IDS_DISPLAY_I, Mems[Memi[ptr]],
+ Mems[Memi[ptr+1]], Mems[Memi[ptr+2]])
+ }
+ } until (button > 0)
+
+ call sfree (sp)
+end
diff --git a/pkg/images/tv/iis/src/clear.x b/pkg/images/tv/iis/src/clear.x
new file mode 100644
index 00000000..60cf69eb
--- /dev/null
+++ b/pkg/images/tv/iis/src/clear.x
@@ -0,0 +1,48 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# CLEAR -- clear certain frames in the display
+
+procedure clear()
+
+char token[SZ_LINE]
+int tok
+short frames[IDS_MAXIMPL+1]
+
+define nexttok 10
+
+include "cv.com"
+
+begin
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+
+ while ( (tok == TOK_IDENTIFIER) || (tok == TOK_NUMBER) ) {
+ if (tok == TOK_IDENTIFIER) {
+ switch (token[1]) {
+ case 'a', 'g':
+ # all colors
+ call cvclearg (short(IDS_EOD), short (IDS_EOD))
+ if (token[1] == 'g')
+ goto nexttok
+ frames[1] = IDS_EOD
+
+ case 'f':
+ call cv_frame (token[2], frames)
+ }
+ } else
+ call cv_frame (token[1], frames)
+
+ call cvcleari (frames)
+ if (token[1] == 'a')
+ return
+
+ # get next token
+nexttok
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+end
diff --git a/pkg/images/tv/iis/src/cv.com b/pkg/images/tv/iis/src/cv.com
new file mode 100644
index 00000000..ec9c70e7
--- /dev/null
+++ b/pkg/images/tv/iis/src/cv.com
@@ -0,0 +1,16 @@
+# common block for cv
+
+pointer cv_gp # file descriptor to write
+pointer cv_stack # working space for escape sequences
+int cv_maxframes # device max frames
+int cv_maxgraph # device max graph planes
+int cv_xcen, cv_ycen # user pixel coords of center of dev.
+int cv_xres, cv_yres # device resolution
+int cv_zres # device z resolution
+real cv_xcon, cv_ycon # conversion from NDC to GKI
+int cv_grch # graphics channel
+real cv_xwinc, cv_ywinc # cursor position for window command
+
+common /cvcom/ cv_gp, cv_stack, cv_maxframes, cv_maxgraph, cv_xcen, cv_ycen,
+ cv_xres, cv_yres, cv_zres, cv_xcon, cv_ycon, cv_grch,
+ cv_xwinc, cv_ywinc
diff --git a/pkg/images/tv/iis/src/cv.h b/pkg/images/tv/iis/src/cv.h
new file mode 100644
index 00000000..80f3016b
--- /dev/null
+++ b/pkg/images/tv/iis/src/cv.h
@@ -0,0 +1,51 @@
+# constants for cv package...should come from a graphcap entry
+
+# These are one based.
+define CV_XCEN 257
+define CV_YCEN 256
+
+define CV_XRES 512
+define CV_YRES 512
+define CV_ZRES 256
+
+define CV_MAXF 4
+define CV_MAXG 7
+
+define CV_GRCHNUM 16
+
+# CVLEN is just the *estimated* never to be exceeded amount of storage needed
+# to set up the escape sequence. It could be determined dynamically by
+# changing cv_move to count elements instead of moving them. Then the known
+# counts would be used with amovs to hustle the elements into the "salloc'ed"
+# space. Instead, with a static count, we can salloc once upon entering
+# the cv program and free up at exit.
+
+define CVLEN 128
+
+# Following are from "display.h"... only SAMPLE_SIZE and MAXLOG needed
+# as of May, 1985. But we might incorporate other programs from "tv",
+# so leave them.
+
+# Size limiting parameters.
+
+define MAXCHAN 2
+define SAMPLE_SIZE 600
+
+# If a logarithmic greyscale transformation is desired, the input range Z1:Z2
+# will be mapped into the range 1.0 to 10.0 ** MAXLOG before taking the log
+# to the base 10.
+
+define MAXLOG 3
+
+# The following parameter is used to compare display pixel coordinates for
+# equality. It determines the maximum permissible magnification. The machine
+# epsilon is not used because the computations are nontrivial and accumulation
+# of error is a problem.
+
+define DS_TOL (1E-4)
+
+# These parameters are needed for user defined transfer functions.
+
+define SZ_BUF 4096
+define STARTPT 0.0E0
+define ENDPT 4095.0E0
diff --git a/pkg/images/tv/iis/src/cv.x b/pkg/images/tv/iis/src/cv.x
new file mode 100644
index 00000000..a169a402
--- /dev/null
+++ b/pkg/images/tv/iis/src/cv.x
@@ -0,0 +1,175 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fio.h>
+include <fset.h>
+include "../lib/ids.h"
+include <gki.h>
+include <ctotok.h>
+include <error.h>
+include "cv.h"
+
+# Captain Video
+
+procedure t_cv()
+
+pointer gp
+char device[SZ_FNAME]
+char command[SZ_LINE]
+
+pointer gopen(), sp
+int dd[LEN_GKIDD]
+
+int scan, tok, envgets()
+
+include "cv.com"
+
+begin
+ call smark (sp)
+ call salloc (cv_stack, CVLEN, TY_SHORT)
+
+ if (envgets ("stdimage", device, SZ_FNAME) == 0)
+ call error (EA_FATAL,
+ "variable 'stdimage' not defined in environment")
+
+ call ids_open (device, dd)
+ call gki_inline_kernel (STDIMAGE, dd)
+ gp = gopen ( device, READ_WRITE, STDIMAGE)
+
+ call fseti (STDIMAGE, F_TYPE, SPOOL_FILE)
+ call fseti (STDIMAGE, F_CANCEL, OK)
+ call ids_grstream (STDIMAGE)
+
+ # to do:
+ # initialize local variables: image display size, etc
+ # instead of defines such as MCXSCALE, etc
+ cv_maxframes = CV_MAXF
+ cv_maxgraph = CV_MAXG
+ cv_xcen = CV_XCEN
+ cv_ycen = CV_YCEN
+ cv_xres = CV_XRES
+ cv_yres = CV_YRES
+ cv_zres = CV_ZRES
+ cv_gp = gp
+ cv_xcon = real(GKI_MAXNDC+1)/CV_XRES
+ cv_ycon = real(GKI_MAXNDC+1)/CV_YRES
+ cv_grch = CV_GRCHNUM
+ cv_xwinc = -1. # Flag: Don't know what lut is
+
+ repeat {
+ call printf (":-) ")
+ call flush (STDOUT)
+ if (scan() == EOF)
+ break
+ call gargtok(tok, command, SZ_LINE)
+ if ((tok == TOK_EOS) || (tok == TOK_NEWLINE))
+ next
+ # decode next command
+ call strlwr(command)
+ switch (command[1]) {
+ case 'x', 'q':
+ break
+
+
+ case 'b':
+ call blink
+
+ case 'c':
+ if (command[2] == 'l')
+ call clear
+ else
+ call rdcur
+
+ case 'd':
+ call display(command[2])
+
+ case 'e': # erase means clear
+ call clear
+
+ case 'h', '?':
+ call help
+
+ # case 'l':
+ # call load
+
+ case 'm':
+ call match
+
+ case 'o':
+ call offset
+
+ case 'p':
+ if ( command[2] == 's')
+ call map(command[2]) # pseudo color
+ else
+ call pan
+
+ case 'r':
+ if (command[2] == 'e')
+ call reset
+ else
+ call range
+
+ case 's':
+ if (command[2] == 'n')
+ call snap
+ else
+ call split
+
+ case 't':
+ call tell
+
+ case 'w':
+ if (command[2] == 'r')
+ call text
+ else
+ call window
+
+ case 'z':
+ call zoom
+
+ default:
+ call eprintf("unknown command: %s\n")
+ call pargstr(command[1])
+
+ } # end switch statement
+
+ } # end repeat statment
+
+ # all done
+
+ call gclose ( gp )
+ call ids_close
+ call sfree (sp)
+end
+
+
+# HELP -- print informative message
+
+procedure help()
+
+begin
+ call eprintf ("--- () : optional; [] : select one; N : number; C/F/Q : see below\n")
+ call eprintf ("b(link) N F (C Q) (F (C Q)..) blink N = 10 is one second\n")
+ call eprintf ("c(ursor) [on off F] cursor\n")
+ call eprintf ("di F (C Q) [on off] display image\n")
+ call eprintf ("dg C (F Q) [on off] display graphics\n")
+ call eprintf ("e(rase) [N a(ll) g(raphics) F] erase (clear)\n")
+ #call eprintf ("l(oad) load a frame\n")
+ call eprintf ("m(atch) (o) F (C) (to) (F) (C) match (output) lookup table\n")
+ call eprintf ("o(ffset) C N offset color N: 0 to +- 4095\n")
+ call eprintf ("p(an) (F) pan images\n")
+ call eprintf ("ps(eudo) (o) (F C) (rn sn) pseudo color mapping rn/sn: random n/seed n\n")
+ call eprintf ("r(ange) N (C) (N C ...) scale image N: 1-8\n")
+ call eprintf ("re(set) [r i t a] reset display registers/image/tables/all\n")
+ call eprintf ("sn(ap) (C) snap a picture\n")
+ call eprintf ("s(plit) [c o px,y nx,y] split picture\n")
+ call eprintf ("t(ell) tell display state\n")
+ call eprintf ("w(indow) (o) (F C) window (output) frames\n")
+ call eprintf ("wr(ite) [F C] text write text to frame/graphics\n")
+ call eprintf ("z(oom) N (F) zoom frames N: 1-8\n")
+ call eprintf ("x or q exit/quit\n")
+ call eprintf ("--- C: letter c followed by r/g/b/a or, for snap r,g,b,m,bw,rgb,\n")
+ call eprintf ("--- or for dg r/g/b/y/p/m/w, as 'cr', 'ca', or 'cgb'\n")
+ call eprintf ("--- F: f followed by a frame number or 'a' for all\n")
+ call eprintf ("--- Q: q followed by quadrant number or t,b,l,r for top, bottom,...\n")
+end
diff --git a/pkg/images/tv/iis/src/cvparse.x b/pkg/images/tv/iis/src/cvparse.x
new file mode 100644
index 00000000..46aba66b
--- /dev/null
+++ b/pkg/images/tv/iis/src/cvparse.x
@@ -0,0 +1,196 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "../lib/ids.h"
+include <ctype.h>
+
+# CVPARSE -- parsing routines for the cv package
+
+# CV_FRAME -- parse a frame specification
+
+procedure cv_frame(str, result)
+
+char str[ARB] # input string
+short result[ARB] # result string
+
+int ip
+int op
+int i
+int used[IDS_MAXIMPL]
+int gused
+
+include "cv.com"
+
+begin
+ if (str[1] == 'a') {
+ result[1] = IDS_EOD
+ return
+ }
+ call aclrs(used,IDS_MAXIMPL)
+ gused = 0
+ op = 1
+ for (ip = 1; str[ip] != EOS; ip = ip + 1) {
+ if (!IS_DIGIT(str[ip])) {
+ if (str[ip] == 'g')
+ gused = 1
+ else {
+ call eprintf("unknown frame specifier: %c\n")
+ call pargc(str[ip])
+ }
+ next
+ }
+ i = TO_INTEG (str[ip]) # fail if > than 9 planes! use ctoi()
+ if ((i < 1) || (i > cv_maxframes) ) {
+ call eprintf ("out of bounds frame: %d\n")
+ call pargi(i)
+ next
+ } else
+ used[i] = 1
+ }
+ do i= 1,IDS_MAXIMPL
+ if (used[i] != 0) {
+ result[op] = i
+ op = op + 1
+ }
+ if (gused != 0) {
+ result[op] = cv_grch
+ op = op + 1
+ }
+ if (op > 1)
+ result[op] = IDS_EOD
+ else
+ result[op] = ERR
+end
+
+
+# CV_COLOR -- parse a color specification
+
+procedure cv_color(str, result)
+
+char str[ARB] # input string
+short result[ARB] # result string
+
+int ip
+int op
+int i
+short val
+short used[IDS_MAXGCOLOR+1]
+
+include "cv.com"
+
+begin
+ if (str[1] == 'a') {
+ result[1] = IDS_EOD
+ return
+ }
+ call aclrs (used, IDS_MAXGCOLOR+1)
+ op = 1
+ for (ip = 1; str[ip] != EOS; ip = ip + 1) {
+ switch (str[ip]) {
+ case 'r':
+ val = IDS_RED
+
+ case 'g':
+ val = IDS_GREEN
+
+ case 'b':
+ val = IDS_BLUE
+
+ case 'y':
+ val = IDS_YELLOW
+
+ case 'w':
+ val = IDS_WHITE
+
+ case 'p':
+ val = IDS_RDBL
+
+ case 'm':
+ val = IDS_GRBL
+
+ default:
+ call eprintf("unknown color: %c\n")
+ call pargc(str[ip])
+ next
+ }
+ used[val] = 1
+ }
+ do i = 1, IDS_MAXGCOLOR+1
+ if (used[i] != 0) {
+ result[op] = i
+ op = op + 1
+ }
+ if (op > 1)
+ result[op] = IDS_EOD
+ else
+ result[op] = ERR
+end
+
+
+# CV_QUAD -- parse a quad specification
+
+procedure cv_quad(str, result)
+
+char str[ARB] # input string
+short result[ARB] # result string
+
+int ip
+int op
+int i
+short used[4]
+
+include "cv.com"
+
+begin
+ if (str[1] == 'a') {
+ result[1] = IDS_EOD
+ return
+ }
+ call aclrs(used, 4)
+ op = 1
+ for (ip = 1; str[ip] != EOS; ip = ip + 1) {
+ if (!IS_DIGIT(str[ip])) {
+ switch(str[ip]) {
+ case 'a':
+ call amovks (1, used, 4)
+
+ case 't':
+ used[1] = 1
+ used[2] = 1
+
+ case 'b':
+ used[3] = 1
+ used[4] = 1
+
+ case 'l':
+ used[2] = 1
+ used[3] = 1
+
+ case 'r':
+ used[1] = 1
+ used[4] = 1
+
+ default:
+ call eprintf("unknown quad specifier: %c\n")
+ call pargc(str[ip])
+ }
+ } else {
+ i = TO_INTEG (str[ip])
+ if ((i < 1) || (i > 4)) {
+ call eprintf ("out of bounds quad: %d\n")
+ call pargi(i)
+ next
+ } else
+ used[i] = 1
+ }
+ }
+ do i = 1,4 {
+ if (used[i] != 0) {
+ result[op] = i
+ op = op + 1
+ }
+ }
+ if (op > 1)
+ result[op] = IDS_EOD
+ else
+ result[op] = ERR
+end
diff --git a/pkg/images/tv/iis/src/cvulut.x b/pkg/images/tv/iis/src/cvulut.x
new file mode 100644
index 00000000..683c9500
--- /dev/null
+++ b/pkg/images/tv/iis/src/cvulut.x
@@ -0,0 +1,130 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <ctype.h>
+include "cv.h"
+
+# CV_ULUT -- Generates a look up table from data supplied by user. The
+# data is read from a two column text file of intensity, greyscale values.
+# The input data are sorted, then mapped to the x range [0-4096]. A
+# piecewise linear look up table of 4096 values is then constructed from
+# the (x,y) pairs given. A pointer to the look up table, as well as the z1
+# and z2 intensity endpoints, is returned.
+
+procedure cv_ulut (fname, z1, z2, lut)
+
+char fname[SZ_FNAME] # Name of file with intensity, greyscale values
+real z1 # Intensity mapped to minimum gs value
+real z2 # Intensity mapped to maximum gs value
+pointer lut # Look up table - pointer is returned
+
+pointer sp, x, y
+int nvalues, i, j, x1, x2, y1
+real delta_gs, delta_xv, slope
+errchk cv_rlut, cv_sort, malloc
+
+begin
+ call smark (sp)
+ call salloc (x, SZ_BUF, TY_REAL)
+ call salloc (y, SZ_BUF, TY_REAL)
+
+ # Read intensities and greyscales from the user's input file. The
+ # intensity range is then mapped into a standard range and the
+ # values sorted.
+
+ call cv_rlut (fname, Memr[x], Memr[y], nvalues)
+ call alimr (Memr[x], nvalues, z1, z2)
+ call amapr (Memr[x], Memr[x], nvalues, z1, z2, STARTPT, ENDPT)
+ call cv_sort (Memr[x], Memr[y], nvalues)
+
+ # Fill lut in straight line segments - piecewise linear
+ call malloc (lut, SZ_BUF, TY_SHORT)
+ do i = 1, nvalues-1 {
+ delta_gs = Memr[y+i] - Memr[y+i-1]
+ delta_xv = Memr[x+i] - Memr[x+i-1]
+ slope = delta_gs / delta_xv
+ x1 = int (Memr[x+i-1])
+ x2 = int (Memr[x+i])
+ y1 = int (Memr[y+i-1])
+ do j = x1, x2-1
+ Mems[lut+j-1] = y1 + slope * (j-x1)
+ }
+
+ call sfree (sp)
+end
+
+
+# CV_RLUT -- Read text file of x, y, values.
+
+procedure cv_rlut (utab, x, y, nvalues)
+
+char utab[SZ_FNAME] # Name of list file
+real x[SZ_BUF] # Array of x values, filled on return
+real y[SZ_BUF] # Array of y values, filled on return
+int nvalues # Number of values in x, y vectors - returned
+
+int n, fd
+pointer sp, lbuf, ip
+real xval, yval
+int getline(), open()
+errchk open, sscan, getline, malloc
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ iferr (fd = open (utab, READ_ONLY, TEXT_FILE))
+ call error (0, "Error opening user table")
+
+ n = 0
+
+ while (getline (fd, Memc[lbuf]) != EOF) {
+ # Skip comment lines and blank lines.
+ if (Memc[lbuf] == '#')
+ next
+ for (ip=lbuf; IS_WHITE(Memc[ip]); ip=ip+1)
+ ;
+ if (Memc[ip] == '\n' || Memc[ip] == EOS)
+ next
+
+ # Decode the points to be plotted.
+ call sscan (Memc[ip])
+ call gargr (xval)
+ call gargr (yval)
+
+ n = n + 1
+ if (n > SZ_BUF)
+ call error (0,
+ "Intensity transformation table cannot exceed 4096 values")
+
+ x[n] = xval
+ y[n] = yval
+ }
+
+ nvalues = n
+ call close (fd)
+ call sfree (sp)
+end
+
+
+# CV_SORT -- Bubble sort of paired arrays.
+
+procedure cv_sort (xvals, yvals, nvals)
+
+real xvals[nvals] # Array of x values
+real yvals[nvals] # Array of y values
+int nvals # Number of values in each array
+
+int i, j
+real temp
+define swap {temp=$1;$1=$2;$2=temp}
+
+begin
+ for (i = nvals; i > 1; i = i - 1)
+ for (j = 1; j < i; j = j + 1)
+ if (xvals[j] > xvals[j+1]) {
+ # Out of order; exchange y values
+ swap (xvals[j], xvals[j+1])
+ swap (yvals[j], yvals[j+1])
+ }
+end
diff --git a/pkg/images/tv/iis/src/cvutil.x b/pkg/images/tv/iis/src/cvutil.x
new file mode 100644
index 00000000..81721081
--- /dev/null
+++ b/pkg/images/tv/iis/src/cvutil.x
@@ -0,0 +1,538 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <gset.h>
+include <gki.h>
+include <imhdr.h>
+include "cv.h"
+include "../lib/ids.h"
+
+# CVUTIL -- utility control routines for cv package
+
+############ CLEAR display ############
+# CVCLEARG -- clear all of graphics (bit) planes
+
+procedure cvclearg (frame, color)
+
+short frame[ARB]
+short color[ARB]
+
+int count
+int cv_move()
+
+include "cv.com"
+
+begin
+ count = cv_move (frame, Mems[cv_stack])
+ count = count + cv_move (color, Mems[cv_stack+count])
+ call gescape (cv_gp, IDS_SET_GP, Mems[cv_stack], count)
+ call gclear (cv_gp)
+end
+
+# CVCLEARI -- clear specified image frames
+
+procedure cvcleari (frames)
+
+short frames[ARB]
+
+include "cv.com"
+
+begin
+ call cv_iset (frames)
+ call gclear (cv_gp)
+end
+
+############ CURSOR and BUTTON ############
+# CV_RDBUT -- read button on trackball (or whatever)
+# if none pressed, will get zero back
+
+int procedure cv_rdbut()
+
+int oldcnum
+real x, y
+int button
+int gstati
+
+include "cv.com"
+
+begin
+ oldcnum = gstati (cv_gp, G_CURSOR)
+ call gseti (cv_gp, G_CURSOR, IDS_BUT_RD)
+ call ggcur (cv_gp, x, y, button)
+ call gseti (cv_gp, G_CURSOR, oldcnum)
+ return(button)
+end
+
+# CV_WTBUT -- wait for button to be pressed, then read it
+
+int procedure cv_wtbut()
+
+int oldcnum
+real x, y
+int button
+int gstati
+
+include "cv.com"
+
+begin
+ oldcnum = gstati (cv_gp, G_CURSOR)
+ call gseti (cv_gp, G_CURSOR, IDS_BUT_WT)
+ call ggcur (cv_gp, x, y, button)
+ call gseti (cv_gp, G_CURSOR, oldcnum)
+ return(button)
+end
+
+# CV_RCUR -- read cursor. The cursor read/set routines do not restore
+# the cursor number...this to avoid numerous stati/seti calls that
+# usually are not needed.
+
+procedure cv_rcur (cnum, x, y)
+
+int cnum
+real x,y
+int junk
+
+include "cv.com"
+
+begin
+ call gseti (cv_gp, G_CURSOR, cnum)
+ call ggcur (cv_gp, x, y, junk)
+end
+
+# CV_SCUR -- set cursor
+
+procedure cv_scur (cnum, x, y)
+
+int cnum
+real x,y
+
+include "cv.com"
+
+begin
+ call gseti (cv_gp, G_CURSOR, cnum)
+ call gscur (cv_gp, x, y)
+end
+
+
+# CV_RCRAW -- read the raw cursor (return actual screen coordinates).
+
+procedure cv_rcraw (x, y)
+
+real x,y
+
+include "cv.com"
+
+begin
+ call cv_rcur (IDS_CRAW, x, y)
+end
+
+# CV_SCRAW -- set raw cursor
+
+procedure cv_scraw (x, y)
+
+real x,y
+
+include "cv.com"
+
+begin
+ call cv_scur (IDS_CRAW, x, y)
+end
+
+
+# cvcur -- turn cursor on or off
+
+procedure cvcur (instruction)
+
+int instruction
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_CURSOR
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = 1
+ Mems[cv_stack+3] = IDS_EOD
+ Mems[cv_stack+4] = IDS_EOD
+ Mems[cv_stack+5] = 1
+ Mems[cv_stack+6] = instruction
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], 7)
+end
+
+############ DISPLAY ############
+# cvdisplay
+
+procedure cvdisplay (instruction, device, frame, color, quad)
+
+int instruction
+int device
+short frame, color, quad
+
+int i
+int cv_move()
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = instruction
+ i = cv_move (frame, Mems[cv_stack+1])
+ i = i + cv_move (color, Mems[cv_stack+1+i])
+ i = i + cv_move (quad, Mems[cv_stack+1+i])
+ call gescape (cv_gp, device, Mems[cv_stack], 1+i)
+end
+
+############ MATCH ############
+# cvmatch -- build match escape sequence
+
+procedure cvmatch (lt, fr, cr, frames, color)
+
+int lt # type
+short fr[ARB] # reference frame and color
+short cr[ARB]
+short frames[ARB] # frames to be changed
+short color[ARB] # and colors
+
+int count, n
+int cv_move()
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_MATCH
+ Mems[cv_stack+1] = lt
+ count = cv_move (fr, Mems[cv_stack+3])
+ count = count + cv_move (cr, Mems[cv_stack+3+count])
+ n = count
+ Mems[cv_stack+count+3] = 0 # unused offset
+ count = count + cv_move (frames, Mems[cv_stack+4+count])
+ count = count + cv_move (color, Mems[cv_stack+4+count])
+ Mems[cv_stack+2] = count - n
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], count+4)
+end
+
+############ OFFSET ############
+# cvoffset -- set offset registers
+
+procedure cvoffset( color, data)
+
+short color[ARB]
+short data[ARB]
+
+int count, cv_move()
+int i
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_OUT_OFFSET
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+3] = IDS_EOD # no-op the frames slot
+ count = cv_move (color, Mems[cv_stack+4])
+ Mems[cv_stack+4+count] = 1 # (unused) offset
+ i = cv_move (data, Mems[cv_stack+5+count])
+ i = i - 1 # don't include EOD of "data"
+ Mems[cv_stack+2] = i
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], i+count+5)
+end
+
+############ PAN ############
+# cvpan -- move the image(s) around
+# The x,y coordinates are NDC that, it is assumed, came from a cursor
+# read, and therefore are of the form
+# ((one_based_pixel-1)/(resolution)) *(GKI_MAXNDC+1) / GKI_MAXNDC
+# The division by GKI_MAXNDC turns into NDC what was GKI ranging from
+# 0 through 511*64 (for IIS) which conforms to the notion of specifying
+# each pixel by its left/bottom GKI boundary.
+
+procedure cvpan (frames, x, y)
+
+short frames[ARB]
+real x,y # position in NDC
+
+int count, cv_move()
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_SCROLL
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = 3
+ count = cv_move (frames, Mems[cv_stack+3])
+ Mems[cv_stack+3+count] = IDS_EOD # all colors
+ Mems[cv_stack+4+count] = 1 # (unused) offset
+ Mems[cv_stack+5+count] = x * GKI_MAXNDC
+ Mems[cv_stack+6+count] = y * GKI_MAXNDC
+ Mems[cv_stack+7+count] = IDS_EOD # for all frames
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], count+8)
+end
+
+############ RANGE ############
+# cvrange -- scale ouput before final look up table
+
+procedure cvrange ( color, range)
+
+short color[ARB]
+short range[ARB]
+
+int cv_move(), count, i
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_RANGE
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+3] = IDS_EOD # all frames
+ count = cv_move (color, Mems[cv_stack+4])
+ Mems[cv_stack+4+count] = 1 # (unused) offset
+ i = cv_move (range, Mems[cv_stack+5+count])
+ i = i - 1 # don't include EOD of "range"
+ Mems[cv_stack+2] = i
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], i+count+5)
+end
+
+############ RESET display ############
+# cvreset -- reset display
+# SOFT -- everything but lookup tables and image/graphics planes
+# MEDIUM -- everything but image/graphics planes
+# HARD -- everything...planes are cleared, all images OFF
+
+procedure cvreset (hardness)
+
+int hardness
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = hardness
+ call gescape (cv_gp, IDS_RESET, Mems[cv_stack], 1)
+end
+
+
+############ SNAP a picture ############
+# cvsnap -- takes a full picture of image display
+
+procedure cvsnap (fname, snap_color)
+
+char fname[ARB] # image file name
+int snap_color
+
+pointer im, immap(), impl2s()
+int i, factor
+real y
+
+include "cv.com"
+
+begin
+ im = immap(fname, NEW_FILE, 0)
+ IM_PIXTYPE(im) = TY_SHORT
+ IM_LEN(im,1) = cv_xres
+ IM_LEN(im,2) = cv_yres
+
+ Mems[cv_stack] = IDS_SNAP
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = 1 # frame, color are not relevant
+ Mems[cv_stack+3] = IDS_EOD
+ Mems[cv_stack+4] = IDS_EOD
+ Mems[cv_stack+5] = 0
+ Mems[cv_stack+6] = snap_color
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], 7)
+
+ factor = cv_yres/10 + 1
+ call eprintf (" (%% done: ")
+ call flush (STDERR)
+ do i = 0, cv_yres-1 {
+ if ( mod(i,factor) == 0) {
+ call eprintf ("%d ")
+ call pargi (int(10*i/cv_yres)*10)
+ call flush (STDERR)
+ }
+ y = real(i)*cv_ycon / GKI_MAXNDC.
+ call ggcell (cv_gp, Mems[impl2s(im,i+1)], cv_xres, 1, 0.0,
+ y, 1.0, y)
+ }
+ call eprintf ("100)\n")
+
+ call imunmap(im)
+ Mems[cv_stack] = IDS_R_SNAPDONE
+ call gescape (cv_gp, IDS_RESET, Mems[cv_stack], 1)
+end
+
+############ SPLIT ############
+# cvsplit -- set split screen position
+
+procedure cvsplit (x, y)
+
+real x,y # NDC coordinates
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_SPLIT
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = 2
+ Mems[cv_stack+3] = IDS_EOD # no-op frame and color
+ Mems[cv_stack+4] = IDS_EOD
+ Mems[cv_stack+5] = 1 # (unused) offset
+ # NOTE multiplacation by MAXNDC+1 ... x, and y, are never == 1.0
+ # ( see split.x)
+ # and truncation effects will work out just right, given what the
+ # image display kernel does with these numbers
+ Mems[cv_stack+6] = x * (GKI_MAXNDC+1)
+ Mems[cv_stack+7] = y * (GKI_MAXNDC+1)
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], 8)
+end
+
+############ TEXT ############
+# Write text
+
+procedure cvtext (x, y, text, size)
+
+real x, y, size
+char text[ARB]
+
+char format[SZ_LINE]
+
+include "cv.com"
+
+begin
+ call sprintf (format, SZ_LINE, "s=%f")
+ call pargr (size)
+ call gtext (cv_gp, x, y, text, format)
+end
+
+############ WHICH ############
+# Tell which frames are one. The best we can do now is
+# tell if any, and if so, which is the "first"
+
+procedure cvwhich (fr)
+
+short fr[ARB]
+
+real x,y
+int cnum, oldcnum
+int gstati
+
+include "cv.com"
+
+begin
+ # Use here the fact that if cursor number is zero, the
+ # kernel will return the number of the first displayed
+ # frame, or "ERR" if none.
+ oldcnum = gstati (cv_gp, G_CURSOR)
+ cnum = 0
+ call gseti (cv_gp, G_CURSOR, cnum)
+ call ggcur (cv_gp, x, y, cnum)
+ call gseti (cv_gp, G_CURSOR, oldcnum)
+ fr[1] = cnum
+ fr[2] = IDS_EOD
+end
+
+############ WLUT ############
+# cvwlut ... change lookup tables
+# the data is in form of line endpoints.
+
+procedure cvwlut (device, frames, color, data, n)
+
+int device
+short frames[ARB]
+short color[ARB]
+short data[ARB]
+int n
+
+int count, cv_move()
+
+include "cv.com"
+
+begin
+ # Device had better refer to a look-up table, or who knows
+ # what will happen!
+ Mems[cv_stack] = device
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = n
+ count = cv_move (frames, Mems[cv_stack+3])
+ count = count + cv_move (color, Mems[cv_stack+3+count])
+ Mems[cv_stack+3+count] = 1 # (unused) offset
+ call amovs (data, Mems[cv_stack+count+4],n)
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], n+count+4)
+end
+
+############ ZOOM ############
+# cvzoom -- zoom the image
+# See comment under PAN about x and y.
+
+procedure cvzoom (frames, power, x, y)
+
+short frames[ARB]
+int power
+real x,y
+
+int count, cv_move()
+
+include "cv.com"
+
+begin
+ Mems[cv_stack] = IDS_ZOOM
+ Mems[cv_stack+1] = IDS_WRITE
+ Mems[cv_stack+2] = 3
+ count = cv_move (frames, Mems[cv_stack+3])
+ Mems[cv_stack+3+count] = IDS_EOD # (unused) color
+ Mems[cv_stack+4+count] = IDS_EOD # (unused) offset
+ Mems[cv_stack+5+count] = power
+ Mems[cv_stack+6+count] = x * GKI_MAXNDC
+ Mems[cv_stack+7+count] = y * GKI_MAXNDC
+ call gescape (cv_gp, IDS_CONTROL, Mems[cv_stack], count+8)
+end
+
+############ SUBROUTINES ##############
+# CV_MOVE -- transfer an array into the escape data array; returns number
+# of items transfered.
+
+int procedure cv_move (in, out)
+
+short in[ARB]
+short out[ARB]
+
+int count
+
+begin
+ count = 0
+ repeat {
+ count = count + 1
+ out[count] = in[count]
+ } until (in[count] == IDS_EOD)
+ return (count)
+end
+
+# CV_ISET -- Tell the image kernel that i/o is to be done for the
+# specified frame/frames.
+
+procedure cv_iset (frames)
+
+short frames[ARB]
+
+short idata[30]
+int i, cv_move()
+
+include "cv.com"
+
+begin
+ i = cv_move (frames, idata)
+ idata[i+1] = IDS_EOD # all bit planes
+ call gescape (cv_gp, IDS_SET_IP, idata, i+1)
+end
+
+# CV_GSET -- Tell the image kernel that i/o is to be done for the
+# specified colors.
+
+procedure cv_gset (colors)
+
+short colors[ARB]
+
+short idata[30]
+int i, cv_move()
+
+include "cv.com"
+
+begin
+ idata[1] = IDS_EOD # all "frames"
+ i = cv_move (colors, idata[2])
+ call gescape (cv_gp, IDS_SET_GP, idata, i+1)
+end
diff --git a/pkg/images/tv/iis/src/display.x b/pkg/images/tv/iis/src/display.x
new file mode 100644
index 00000000..d04b1365
--- /dev/null
+++ b/pkg/images/tv/iis/src/display.x
@@ -0,0 +1,104 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# DISPLAY -- Turn frames on or off
+
+procedure display(command)
+
+char command[ARB]
+
+int tok
+char token[SZ_LINE]
+short color[IDS_MAXGCOLOR+1]
+short frames[IDS_MAXIMPL+1]
+short quad[5]
+short instruction
+int escape
+include "cv.com"
+
+begin
+ if (command[1] == 'i')
+ escape = IDS_DISPLAY_I
+ else if (command[1] == 'g')
+ escape = IDS_DISPLAY_G
+ else {
+ call eprintf ("Only 'di' or 'dg' are understood\n")
+ return
+ }
+
+ instruction = ERR
+ frames[1] = ERR
+ color[1] = ERR
+ quad[1] = IDS_EOD
+
+ repeat {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if ( tok == TOK_IDENTIFIER) {
+ switch (token[1]) {
+ case 'c':
+ call cv_color (token[2], color)
+ if (color[1] == ERR)
+ return
+
+ case 'f':
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+
+
+ case 'o':
+ if (token[2] == 'n')
+ instruction = IDS_ON
+ else if (token[2] == 'f')
+ instruction = IDS_OFF
+
+ case 'q':
+ call cv_quad (token[2], quad)
+ if (quad[1] == ERR)
+ return
+ }
+ } else if (tok == TOK_NUMBER) {
+ call cv_frame (token[1], frames)
+ if (frames[1] == ERR)
+ return
+ }
+ } until ( tok == TOK_NEWLINE )
+
+
+ # Require a frame number, but allow default of color and quad to "all".
+ # But, for graphics, default the frame and require a color.
+ # In either case, for OFF, allow all defaults.
+ if (escape == IDS_DISPLAY_I) {
+ if ((instruction == IDS_OFF) && (frames[1] == ERR))
+ frames[1] = IDS_EOD
+ if ( color[1] == ERR)
+ color[1] = IDS_EOD
+ } else {
+ if ((instruction == IDS_OFF) && ( color[1] == ERR) )
+ color[1] = IDS_EOD
+ if ( frames[1] == ERR)
+ frames[1] = IDS_EOD
+ }
+
+ if (frames[1] == ERR) {
+ call eprintf ("Frame specification required\n")
+ return
+ }
+ if (color[1] == ERR) {
+ call eprintf ("Color specification required\n")
+ return
+ }
+
+ # if neither "on" nor "off", then turn off all, and turn
+ # on the specified frames
+ if (instruction == ERR) {
+ call cvdisplay (IDS_OFF , escape, short(IDS_EOD),
+ short(IDS_EOD), short(IDS_EOD))
+ instruction = IDS_ON
+ }
+ call cvdisplay (instruction, escape, frames, color, quad)
+end
diff --git a/pkg/images/tv/iis/src/gwindow.h b/pkg/images/tv/iis/src/gwindow.h
new file mode 100644
index 00000000..5050b304
--- /dev/null
+++ b/pkg/images/tv/iis/src/gwindow.h
@@ -0,0 +1,34 @@
+# Window descriptor structure.
+
+define LEN_WDES (5+(W_MAXWC+1)*LEN_WC+80)
+define LEN_WC 10 # 4=[XbXeYbYe]+2=tr_type[xy]
+define W_MAXWC 5 # max world coord systems
+define W_SZIMSECT 79 # image section string
+
+define W_DEVICE Memi[$1]
+define W_FRAME Memi[$1+1] # device frame number
+define W_XRES Memi[$1+2] # device resolution, x
+define W_YRES Memi[$1+3] # device resolution, y
+define W_WC ($1+$2*LEN_WC+5) # ptr to coord descriptor
+define W_IMSECT Memc[($1+65-1)*SZ_STRUCT+1]
+
+# Fields of the WC coordinate descriptor, a substructure of the window
+# descriptor. "W_XB(W_WC(w,0))" is the XB field of wc 0 of window W.
+
+define W_XS Memr[P2R($1)] # starting X value
+define W_XE Memr[P2R($1+1)] # ending X value
+define W_XT Memi[$1+2] # X transformation type
+define W_YS Memr[P2R($1+3)] # starting Y value
+define W_YE Memr[P2R($1+4)] # ending Y value
+define W_YT Memi[$1+5] # Y transformation type
+define W_ZS Memr[P2R($1+6)] # starting Z value (greyscale)
+define W_ZE Memr[P2R($1+7)] # ending Z value
+define W_ZT Memi[$1+8] # Z transformation type
+define W_UPTR Memi[$1+9] # LUT when ZT=USER
+
+# Types of coordinate and greyscale transformations.
+
+define W_UNITARY 0 # values map without change
+define W_LINEAR 1 # linear mapping
+define W_LOG 2 # logarithmic mapping
+define W_USER 3 # user specifies transformation
diff --git a/pkg/images/tv/iis/src/load1.x b/pkg/images/tv/iis/src/load1.x
new file mode 100644
index 00000000..c33cc1dd
--- /dev/null
+++ b/pkg/images/tv/iis/src/load1.x
@@ -0,0 +1,324 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+#### load1.x (from load.x) ####
+
+include <mach.h>
+include <imset.h>
+include <imhdr.h>
+include <error.h>
+include <gki.h>
+include <fio.h>
+include <fset.h>
+include "gwindow.h"
+include "../lib/ids.h"
+include "cv.h"
+
+# LOAD - Load an image. The specified image section is mapped into
+# the specified section of an image display frame. The mapping involves
+# a linear transformation in X and Y and a linear or logarithmic transformation
+# in Z (greyscale). Images of all pixel datatypes are supported, and there
+# no upper limit on the size of an image. The display device is interfaced
+# via GIO metacode.
+
+procedure t_load()
+
+char image[SZ_FNAME]
+short frame[IDS_MAXIMPL+1]
+bool frame_erase, border_erase
+pointer im, wdes, sp
+
+pointer gp
+char device[SZ_FNAME]
+int dd[LEN_GKIDD]
+
+int envgets()
+short clgets()
+bool clgetb()
+pointer immap(), gopen()
+
+include "cv.com"
+errchk immap, imunmap, ds_getparams
+
+begin
+ call smark (sp)
+ call salloc (cv_stack, CVLEN, TY_SHORT)
+ call salloc (wdes, LEN_WDES, TY_STRUCT)
+
+ if (envgets ("stdimage", device, SZ_FNAME) == 0)
+ call error (EA_FATAL,
+ "variable 'stdimage' not defined in environment")
+
+ call ids_open (device, dd)
+ call gki_inline_kernel (STDIMAGE, dd)
+ # Need READ_WRITE so can call cvdisplay
+ gp = gopen ( device, READ_WRITE, STDIMAGE)
+
+ call fseti (STDIMAGE, F_TYPE, SPOOL_FILE)
+ call fseti (STDIMAGE, F_CANCEL, OK)
+ call ids_grstream (STDIMAGE)
+
+ # to do:
+ # initialize local variables: image display size, etc
+ # instead of defines such as MCXSCALE, etc
+
+ cv_maxframes = CV_MAXF
+ cv_maxgraph = CV_MAXG
+ cv_xcen = CV_XCEN
+ cv_ycen = CV_YCEN
+ cv_xres = CV_XRES
+ cv_yres = CV_YRES
+ cv_zres = CV_ZRES
+ cv_gp = gp
+ cv_xcon = real(GKI_MAXNDC+1)/CV_XRES
+ cv_ycon = real(GKI_MAXNDC+1)/CV_YRES
+ cv_grch = CV_GRCHNUM
+ cv_xwinc = -1. # Flag: Don't know what lut is
+
+ # Open input imagefile.
+ call clgstr ("image", image, SZ_FNAME)
+ im = immap (image, READ_ONLY, 0)
+
+ # Ultimately, we should get a sequence of frames, all of which get
+ # loaded with the same image.
+
+ frame[1] = clgets ("frame")
+ frame[2] = IDS_EOD
+ frame_erase = clgetb ("erase")
+
+ # Optimize for sequential i/o.
+ call imseti (im, IM_ADVICE, SEQUENTIAL)
+
+ # The frame being displayed does not necessarily change when a new
+ # frame is loaded. (We might consider letting user select via the
+ # cv package)
+
+ if (clgetb ("select_frame")) {
+ call cvdisplay (IDS_OFF, IDS_DISPLAY_I, short(IDS_EOD),
+ short(IDS_EOD), short(IDS_EOD))
+ call cvdisplay (IDS_ON, IDS_DISPLAY_I, frame, short(IDS_EOD),
+ short(IDS_EOD))
+ }
+
+ if (frame_erase)
+ call cvcleari (frame)
+
+ # Tell GIO what frame(s) to write
+ call cv_iset (frame)
+
+ # Done with all possible read/write calls to cv package. Fix up so
+ # don't read device if we erase the frame, so need WRITE_ONLY mode.
+ # fseti on STDIMAGE didn't work.
+
+ if (frame_erase) {
+ call gclose (gp)
+ call gki_inline_kernel (STDIMAGE, dd)
+ gp = gopen ( device, WRITE_ONLY, STDIMAGE)
+ cv_gp = gp
+ call fseti (STDIMAGE, F_TYPE, SPOOL_FILE)
+ call fseti (STDIMAGE, F_CANCEL, OK)
+ }
+
+ # Get display parameters and set up transformation.
+ call ds_getparams (im, wdes, image, frame)
+
+ # Erase the border (space between displayed image section and edge of
+ # window) only if screen was not erased and border erasing is enabled.
+
+ if (frame_erase)
+ border_erase = false
+ else
+ border_erase = clgetb ("border_erase")
+
+ # Display the image.
+ call ds_load_display (im, wdes, border_erase)
+
+ call imunmap (im)
+
+ # All done.
+ call gclose (gp)
+ call ids_close()
+ call sfree (sp)
+end
+
+
+# DS_GETPARAMS -- Get the parameters controlling how the image is mapped
+# into the display frame. Set up the transformations and save in the graphics
+# descriptor file.
+
+procedure ds_getparams (im, wdes, image, frame)
+
+pointer im, wdes # Image and graphics descriptors
+char image[SZ_FNAME] # Should be determined from im
+short frame[ARB]
+
+bool fill, zscale_flag, zrange_flag, zmap_flag
+real xcenter, ycenter
+real xsize, ysize, pxsize, pysize
+real xmag, ymag, xscale, yscale
+real z1, z2, contrast
+int nsample_lines, ncols, nlines, len_stdline
+pointer sp, w, ztrans, lut, lutfile
+
+bool clgetb()
+int clgeti()
+real clgetr()
+bool streq()
+
+include "cv.com"
+
+begin
+ call smark (sp)
+ call salloc (ztrans, SZ_FNAME, TY_CHAR)
+
+ # Set up a new graphics descriptor structure defining the coordinate
+ # transformation used to map the image into the display frame.
+
+ call strcpy (image, W_IMSECT(wdes), W_SZIMSECT)
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+
+ # The fill, zscale, and zrange parameters determine the algorithms to
+ # be used to scale the image in the spatial and greyscale dimensions.
+ # If greyscale mapping is disabled the zscale and zrange options are
+ # disabled. Greyscale mapping can also be disabled by turning off
+ # zscale and zrange and setting Z1 and Z2 to the device greyscale min
+ # and max values, producing a unitary transformation.
+
+ fill = clgetb ("fill")
+ call clgstr ("ztrans", Memc[ztrans], SZ_FNAME)
+ if (streq (Memc[ztrans], "none") || streq (Memc[ztrans], "user")) {
+ zscale_flag = false
+ zrange_flag = false
+ zmap_flag = false
+ } else {
+ zmap_flag = true
+ zscale_flag = clgetb ("zscale")
+ if (!zscale_flag)
+ zrange_flag = clgetb ("zrange")
+ }
+
+ # Determine Z1 and Z2, the range of input greylevels to be mapped into
+ # the fixed range of display greylevels.
+
+ if (zscale_flag) {
+ # Autoscaling is desired. Compute Z1 and Z2 which straddle the
+ # median computed by sampling a portion of the image.
+
+ contrast = clgetr ("contrast")
+ nsample_lines = clgeti ("nsample_lines")
+ len_stdline = SAMPLE_SIZE / nsample_lines
+ call zscale (im, z1, z2, contrast, SAMPLE_SIZE, len_stdline)
+
+ } else if (zrange_flag) {
+ nsample_lines = clgeti ("nsample_lines")
+ call maxmin (im, z1, z2, nsample_lines)
+
+ } else if (zmap_flag) {
+ z1 = clgetr ("z1")
+ z2 = clgetr ("z2")
+ }
+
+ # Determine the display window into which the image is to be mapped
+ # in normalized device coordinates.
+
+ xcenter = max(0.0, min(1.0, clgetr ("xcenter")))
+ ycenter = max(0.0, min(1.0, clgetr ("ycenter")))
+ xsize = max(0.0, min(1.0, clgetr ("xsize")))
+ ysize = max(0.0, min(1.0, clgetr ("ysize")))
+
+ # Determine X and Y scaling ratios required to map the image into the
+ # normalized display window. If spatial scaling is not desired filling
+ # must be disabled and XMAG and YMAG must be set to 1.0 in the
+ # parameter file. Fill mode will always produce an aspect ratio of 1;
+ # if nonequal scaling is required then the magnification ratios must
+ # be set explicitly by the user.
+
+ if (fill) {
+ # Compute scale in units of window coords per data pixel required
+ # to scale image to fit window.
+
+ xscale = xsize / max (1, (ncols - 1))
+ yscale = ysize / max (1, (nlines - 1))
+
+ if (xscale < yscale)
+ yscale = xscale
+ else
+ xscale = yscale
+
+ } else {
+ # Compute scale required to provide image magnification ratios
+ # specified by the user. Magnification is specified in units of
+ # display pixels, i.e, a magnification ratio of 1.0 means that
+ # image pixels will map to display pixels without scaling.
+
+ xmag = clgetr ("xmag")
+ ymag = clgetr ("ymag")
+ xscale = 1.0 / ((cv_xres - 1) / xmag)
+ yscale = 1.0 / ((cv_yres - 1) / ymag)
+ }
+
+ # Set device window limits in normalized device coordinates.
+ # World coord system 0 is used for the device window.
+
+ w = W_WC(wdes,0)
+ W_XS(w) = xcenter - xsize / 2.0
+ W_XE(w) = xcenter + xsize / 2.0
+ W_YS(w) = ycenter - ysize / 2.0
+ W_YE(w) = ycenter + ysize / 2.0
+
+ # Set pixel coordinates of window, world coordinate system #1.
+
+ w = W_WC(wdes,1)
+ pxsize = xsize / xscale
+ pysize = ysize / yscale
+
+ # If the image is too large to fit in the window given the scaling
+ # factors XSCALE and YSCALE, the following will set starting and ending
+ # pixel coordinates in the interior of the image. If the image is too
+ # small to fill the window then the pixel coords will reference beyond
+ # the bounds of the image.
+
+ W_XS(w) = (ncols - 1) / 2.0 + 1 - (pxsize / 2.0)
+ W_XE(w) = W_XS(w) + pxsize
+ W_YS(w) = (nlines - 1) / 2.0 + 1 - (pysize / 2.0)
+ W_YE(w) = W_YS(w) + pysize
+
+ # All spatial transformations are linear.
+ W_XT(w) = W_LINEAR
+ W_YT(w) = W_LINEAR
+
+ # Determine whether a log or linear greyscale transformation is
+ # desired.
+ if (streq (Memc[ztrans], "log"))
+ W_ZT(w) = W_LOG
+ else if (streq (Memc[ztrans], "linear"))
+ W_ZT(w) = W_LINEAR
+ else if (streq (Memc[ztrans], "none"))
+ W_ZT(w) = W_UNITARY
+ else if (streq (Memc[ztrans], "user")) {
+ W_ZT(w) = W_USER
+ call salloc (lutfile, SZ_FNAME, TY_CHAR)
+ call clgstr ("lutfile", Memc[lutfile], SZ_FNAME)
+ call cv_ulut (Memc[lutfile], z1, z2, lut)
+ W_UPTR(w) = lut
+ } else {
+ call eprintf ("Bad greylevel transformation '%s'\n")
+ call pargstr (Memc[ztrans])
+ W_ZT(w) = W_LINEAR
+ }
+
+ # Set up the greyscale transformation.
+ W_ZS(w) = z1
+ W_ZE(w) = z2
+
+ # Tell the user what values were used.
+ call printf ("cvl: z1 %6.1f, z2 %6.1f\n")
+ call pargr (z1)
+ call pargr (z2)
+
+ # The user world coordinate system should be set from the CTRAN
+ # structure in the image header, but for now we just make it equal
+ # to the pixel coordinate system.
+
+ call amovi (Memi[w], Memi[W_WC(wdes,2)], LEN_WC)
+end
diff --git a/pkg/images/tv/iis/src/load2.x b/pkg/images/tv/iis/src/load2.x
new file mode 100644
index 00000000..5372907f
--- /dev/null
+++ b/pkg/images/tv/iis/src/load2.x
@@ -0,0 +1,335 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+#### load2.x (from load.x) ####
+
+include <mach.h>
+include <imset.h>
+include <imhdr.h>
+include <error.h>
+include <gki.h>
+include <fio.h>
+include <fset.h>
+include "gwindow.h"
+include "../lib/ids.h"
+include "cv.h"
+
+# DS_LOAD_DISPLAY -- Map an image into the display window. In general this
+# involves independent linear transformations in the X, Y, and Z (greyscale)
+# dimensions. If a spatial dimension is larger than the display window then
+# the image is block averaged. If a spatial dimension or a block averaged
+# dimension is smaller than the display window then linear interpolation is
+# used to expand the image. Both the input image and the output device appear
+# to us as images, accessed via IMIO.
+#
+# World coordinate system 0 (WCS 0) defines the position and size of the device
+# window in NDC coordinates (0-1 in either axis). WCS 1 assigns a pixel
+# coordinate system to the same window. If we convert the NDC coordinates of
+# the window into device coordinates in pixels, then the ratios of the window
+# coordinates in pixels to the image coordinates in pixels defines the real
+# magnification factors for the two spatial axes. If the pixel coordinates
+# are out of bounds then the image will be displayed centered in the window
+# with zero fill at the edges. If the frame has not been erased then the fill
+# areas must be explicitly zeroed.
+
+procedure ds_load_display (im, wdes, border_erase)
+
+pointer im # input image
+pointer wdes # graphics window descriptor
+bool border_erase
+
+int wx1, wx2, wy1, wy2 # device window to be filled with image data
+real px1, px2, py1, py2 # image coords in fractional image pixels
+real pxsize, pysize # size of image section in fractional pixels
+real wxcenter, wycenter # center of device window in frac device pixels
+real xmag, ymag # x,y magnification ratios
+pointer w0, w1 # world coord systems 0 (NDC) and 1 (pixel)
+
+include "cv.com"
+
+begin
+ # Compute pointers to WCS 0 and 1.
+ w0 = W_WC(wdes,0)
+ w1 = W_WC(wdes,1)
+
+ # Compute X and Y magnification ratios required to map image into
+ # the device window in device pixel units.
+
+ xmag = (W_XE(w0) - W_XS(w0)) * cv_xres / (W_XE(w1) - W_XS(w1))
+ ymag = (W_YE(w0) - W_YS(w0)) * cv_yres / (W_YE(w1) - W_YS(w1))
+
+ # Compute the coordinates of the image section to be displayed.
+ # This is not necessarily the same as WCS 1 since the WCS coords
+ # need not be inbounds.
+
+ px1 = max (1.0, W_XS(w1))
+ px2 = min (real (IM_LEN(im,1)), W_XE(w1))
+ py1 = max (1.0, W_YS(w1))
+ py2 = min (real (IM_LEN(im,2)), W_YE(w1))
+
+ # Now compute the coordinates of the image section to be written in
+ # device pixel units. This section must lie within or on the device
+ # window.
+ # This computation for I2S will give 257, which does differ by one
+ # for the Y center (due to inversion in I2S). This should not matter,
+ # but if it does, this comment will change!
+
+ pxsize = px2 - px1
+ pysize = py2 - py1
+ wxcenter = (W_XE(w0) + W_XS(w0)) / 2.0 * cv_xres + 1
+ wycenter = (W_YE(w0) + W_YS(w0)) / 2.0 * cv_yres + 1
+
+ wx1 = max (1, int (wxcenter - (pxsize / 2.0 * xmag)))
+ wx2 = max (wx1, min (cv_xres, int (wx1 + (pxsize * xmag))))
+ wy1 = max (1, int (wycenter - (pysize / 2.0 * ymag)))
+ wy2 = max (wy1, min (cv_yres, int (wy1 + (pysize * ymag))))
+
+ # Display the image data, ignoring zero filling at the boundaries.
+
+ call ds_map_image (im, px1,px2,py1,py2, wx1,wx2,wy1,wy2,
+ W_ZS(w1), W_ZE(w1), W_ZT(w1), W_UPTR(w1))
+
+ # Zero the border of the window if the frame has not been erased,
+ # and if the displayed section does not occupy the full window.
+
+ if (border_erase)
+ call ds_erase_border (im, wdes, wx1,wx2,wy1,wy2)
+end
+
+
+# DS_MAP_IMAGE -- Map an image section from the input image to a section
+# (window) of the output image (the display device). All spatial scaling is
+# handled by the "scaled input" package, i.e., SIGL2[SR]. Our task is to
+# get lines from the scaled input image, transform the greyscale if necessary,
+# and write the lines to the output device.
+
+procedure ds_map_image (im, px1,px2,py1,py2, wx1,wx2,wy1,wy2, z1,z2,zt, uptr)
+
+pointer im # input image
+real px1,px2,py1,py2 # input section
+int wx1,wx2,wy1,wy2 # output section
+real z1,z2 # range of input greylevels to be mapped.
+int zt # log or linear greylevel transformation
+pointer uptr # pointer to user transformation table
+
+bool unitary_greyscale_transformation
+short lut1, lut2, z1_s, z2_s, dz1_s, dz2_s
+real dz1, dz2
+int wy, nx, ny, xblk, yblk
+pointer in, out, si
+pointer sigl2s(), sigl2r(), sigl2_setup()
+errchk sigl2s, sigl2r, sigl2_setup
+real xs, xe, y
+pointer sp, outr
+bool fp_equalr()
+real if_elogr()
+extern if_elogr
+
+include "cv.com"
+
+begin
+ call smark (sp)
+
+ # Set up for scaled image input.
+
+ nx = wx2 - wx1 + 1
+ ny = wy2 - wy1 + 1
+ xblk = INDEFI
+ yblk = INDEFI
+ si = sigl2_setup (im, px1,px2,nx,xblk, py1,py2,ny,yblk)
+
+ # Output array, and limiting x values in NDC
+
+ call salloc (out, nx, TY_SHORT)
+ xs = real(wx1 - 1) * cv_xcon / GKI_MAXNDC
+ # Don't subtract 1 from wx2 as we want it to be first one not filled
+ xe = real(wx2) * cv_xcon / GKI_MAXNDC
+ if ( xe > 1.0)
+ xe = 1.0
+
+ # The device ZMIN and ZMAX parameters define the acceptable range
+ # of greyscale values for the output device (e.g., 0-255 for most 8-bit
+ # display devices). For the general display, we use 0 and the
+ # device "z" resolution. Values Z1 and Z2 are mapped linearly or
+ # logarithmically into these.
+
+ dz1 = 0
+ dz2 = cv_zres-1
+
+ # If the user specified the transfer function, see that the
+ # intensity and greyscale values are in range.
+
+ if (zt == W_USER) {
+ call alims (Mems[uptr], SZ_BUF, lut1, lut2)
+ dz1_s = short (dz1)
+ dz2_s = short (dz2)
+ if (lut2 < dz1_s || lut1 > dz2_s)
+ call eprintf ("User specified greyscales out of range\n")
+ if (z2 < IM_MIN(im) || z1 > IM_MAX(im))
+ call eprintf ("User specified intensities out of range\n")
+ }
+
+ # Type short pixels are treated as a special case to minimize vector
+ # operations for such images (which are common). If the image pixels
+ # are either short or real then only the ALTR (greyscale transformation)
+ # vector operation is required. The ALTR operator linearly maps
+ # greylevels in the range Z1:Z2 to DZ1:DZ2, and does a floor ceiling
+ # of DZ1:DZ2 on all pixels outside the range. If unity mapping is
+ # employed the data is simply copied, i.e., floor ceiling constraints
+ # are not applied. This is very fast and will produce a contoured
+ # image on the display which will be adequate for some applications.
+
+ if (zt == W_UNITARY)
+ unitary_greyscale_transformation = true
+ else
+ unitary_greyscale_transformation =
+ (fp_equalr (dz1,z1) && fp_equalr (dz2,z2)) || fp_equalr (z1,z2)
+
+ if (IM_PIXTYPE(im) == TY_SHORT && zt != W_LOG) {
+
+ # Set dz1_s and dz2_s depending on transformation
+ if (zt != W_USER) {
+ dz1_s = short (dz1)
+ dz2_s = short (dz2)
+ } else {
+ dz1_s = short (STARTPT)
+ dz2_s = short (ENDPT)
+ }
+ z1_s = short (z1)
+ z2_s = short (z2)
+
+ for (wy=wy1; wy <= wy2; wy=wy+1) {
+ in = sigl2s (si, wy - wy1 + 1)
+ y = real(wy-1) * cv_ycon / GKI_MAXNDC
+ if (unitary_greyscale_transformation)
+ call gpcell (cv_gp, Mems[in], nx, 1, xs, y, xe, y)
+ else if (zt == W_USER) {
+ call amaps (Mems[in], Mems[out], nx, z1_s,z2_s, dz1_s,dz2_s)
+ call aluts (Mems[out], Mems[out], nx, Mems[uptr])
+ call gpcell (cv_gp, Mems[out], nx, 1, xs, y, xe, y)
+ } else {
+ call amaps (Mems[in], Mems[out], nx, z1_s,z2_s, dz1_s,dz2_s)
+ call gpcell (cv_gp, Mems[out], nx, 1, xs, y, xe, y)
+ }
+ }
+ } else {
+ call salloc (outr, nx, TY_REAL)
+ for (wy=wy1; wy <= wy2; wy=wy+1) {
+ in = sigl2r (si, wy - wy1 + 1)
+ y = real(wy - 1) * cv_ycon / GKI_MAXNDC
+
+ if (zt == W_LOG) {
+ call amapr (Memr[in], Memr[outr], nx,
+ z1, z2, 1.0, 10.0 ** MAXLOG)
+ call alogr (Memr[outr], Memr[outr], nx, if_elogr)
+ call amapr (Memr[outr], Memr[outr], nx,
+ 1.0, real(MAXLOG), dz1, dz2)
+ call achtrs (Memr[outr], Mems[out], nx)
+ } else if (unitary_greyscale_transformation) {
+ call achtrs (Memr[in], Mems[out], nx)
+ } else if (zt == W_USER) {
+ call amapr (Memr[in], Memr[outr], nx, z1,z2, STARTPT,ENDPT)
+ call achtrs (Memr[outr], Mems[out], nx)
+ call aluts (Mems[out], Mems[out], nx, Mems[uptr])
+ } else {
+ call amapr (Memr[in], Memr[outr], nx, z1, z2, dz1, dz2)
+ call achtrs (Memr[outr], Mems[out], nx)
+ }
+ call gpcell (cv_gp, Mems[out], nx, 1, xs, y, xe, y)
+ }
+ }
+
+ call sfree (sp)
+ call sigl2_free (si)
+end
+
+
+# DS_ERASE_BORDER -- Zero the border of the window if the frame has not been
+# erased, and if the displayed section does not occupy the full window.
+# It would be more efficient to do this while writing the greyscale data to
+# the output image, but that would complicate the display procedures and frames
+# are commonly erased before displaying an image.
+
+procedure ds_erase_border (im, wdes, wx1,wx2,wy1,wy2)
+
+pointer im # input image
+pointer wdes # window descriptor
+int wx1,wx2,wy1,wy2 # section of display window filled by image data
+
+int dx1,dx2,dy1,dy2 # coords of full display window in device pixels
+int j, n, n1
+pointer w0
+pointer sp, zero
+real xls, xle, xrs, xre, y
+
+include "cv.com"
+
+begin
+ call smark (sp)
+ call salloc (zero, cv_xres, TY_SHORT)
+ call aclrs (Mems[zero], cv_xres)
+
+ # Compute device pixel coordinates of the full display window.
+ w0 = W_WC(wdes,0)
+ dx1 = W_XS(w0) * (cv_xres - 1) + 1
+ dx2 = W_XE(w0) * (cv_xres - 1) + 1
+ dy1 = W_YS(w0) * (cv_yres - 1) + 1
+ dy2 = W_YE(w0) * (cv_yres - 1) + 1
+
+ # Determine left and right (exclusive), start and end, x values in NDC
+ # for pixels not already filled.
+ # If, say, dx1 < wx1, we want to clear dx1 through wx1-1, which means
+ # that for gpcell, we want the (right) end points to be the first
+ # pixel not cleared.
+ xls = real(dx1 - 1) * cv_xcon / GKI_MAXNDC
+ xle = real(wx1) * cv_xcon / GKI_MAXNDC
+ if (xle > 1.0)
+ xle = 1.0
+ xre = real(dx2 - 1) * cv_xcon / GKI_MAXNDC
+ xrs = real(wx2) * cv_xcon / GKI_MAXNDC
+ if (xre > 1.0)
+ xre = 1.0
+
+ # Erase lower margin.
+ n = dx2 - dx1 + 1
+ for (j=dy1; j < wy1; j=j+1) {
+ y = real(j-1) * cv_ycon / GKI_MAXNDC
+ call gpcell (cv_gp, Mems[zero], n, 1, xls, y, xre, y)
+ }
+
+ # Erase left and right margins. By doing the right margin of a line
+ # immediately after the left margin we have a high liklihood that the
+ # display line will still be in the FIO buffer.
+
+ n = wx1 - dx1
+ n1 = dx2 - wx2
+ for (j=wy1; j <= wy2; j=j+1) {
+ y = real(j-1) * cv_ycon / GKI_MAXNDC
+ if (dx1 < wx1)
+ call gpcell (cv_gp, Mems[zero], n, 1, xls, y, xle, y)
+ if (wx2 < dx2)
+ call gpcell (cv_gp, Mems[zero], n1, 1, xrs, y, xre, y)
+ }
+
+ # Erase upper margin.
+ n = dx2 - dx1 + 1
+ for (j=wy2+1; j <= dy2; j=j+1) {
+ y = real(j-1) * cv_ycon / GKI_MAXNDC
+ call gpcell (cv_gp, Mems[zero], n, 1, xls, y, xre, y)
+ }
+
+ call sfree (sp)
+end
+
+
+# IF_ELOG -- The error function for log10. Note that MAX_EXPONENT is
+# currently an integer so it is converted to the appropriate data type
+# before being returned.
+
+real procedure if_elogr (x)
+
+real x # the input pixel value
+
+begin
+ return (real(-MAX_EXPONENT))
+end
+
diff --git a/pkg/images/tv/iis/src/map.x b/pkg/images/tv/iis/src/map.x
new file mode 100644
index 00000000..5ea7c230
--- /dev/null
+++ b/pkg/images/tv/iis/src/map.x
@@ -0,0 +1,320 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# MAP -- set fixed or variable LUT mapping
+
+procedure map(command)
+
+char command[ARB]
+
+char token[SZ_LINE]
+int tok
+short frames[IDS_MAXIMPL+2] # frames, graphics, EOD
+short colors[IDS_MAXGCOLOR]
+int device
+short pcolor[2]
+real limit
+long seed
+real urand(), xfactor
+int ctoi()
+int i, ip, iseed, level, nchar
+bool triangle
+pointer sp, rdata, gdata, bdata, rp, gp, bp
+
+include "cv.com"
+
+begin
+ # Find out if want to change output tables
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (( tok == TOK_IDENTIFIER) && (token[1] == 'o' )) {
+ device = IDS_OUTPUT_LUT
+ } else {
+ device = IDS_FRAME_LUT
+ # reset input pointers; same as having pushed back token
+ call reset_scan
+ call gargtok (tok, token, SZ_LINE)
+ }
+
+ # Default to all frames, all colors
+ frames[1] = IDS_EOD
+ colors[1] = IDS_EOD
+ triangle = true # default to simple three function type
+ seed = -1
+ level = 8
+
+ # which frames to change, colors, etc
+
+ repeat {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'f') {
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (token[1] == 'c') {
+ call cv_color (token[2], colors)
+ if (colors[1] == ERR)
+ return
+ } else if (token[1] == 'r') { # (random) level count
+ ip = 2
+ nchar = ctoi (token, ip, level)
+ if (nchar <= 0) {
+ call eprintf ("Incorrect random count: %s\n")
+ call pargstr (token[2])
+ return
+ }
+ if (level < 4)
+ level = 4
+ else if (level > 128)
+ level = 128
+ triangle = false
+ } else if (token[1] == 's') { # seed
+ ip = 2
+ nchar = ctoi (token, ip, iseed)
+ if (nchar <= 0) {
+ call eprintf ("Incorrect seed: %s\n")
+ call pargstr (token[2])
+ return
+ }
+ seed = iseed
+ triangle = false
+ } else {
+ call eprintf ("Unknown map argument: %s\n")
+ call pargstr (token)
+ return
+ }
+ } else if (tok != TOK_NEWLINE) {
+ call eprintf ("Unexpected map input: %s\n")
+ call pargstr (token)
+ return
+ }
+ } until ( tok == TOK_NEWLINE)
+
+ pcolor[2] = IDS_EOD
+ # Sorry, but we "know" that ofm shouldn't go beyond first
+ # 256 for common NOAO use.
+ if ( device == IDS_FRAME_LUT)
+ limit = 1.0
+ else
+ limit = 0.25
+
+ # Build the three functions and load them.
+ # First, expand colors if using all
+
+ if (colors[1] == IDS_EOD) {
+ colors[1] = IDS_RED
+ colors[2] = IDS_GREEN
+ colors[3] = IDS_BLUE
+ colors[4] = IDS_EOD
+ }
+
+ # if standard pseudocolor, let kodak do it
+
+ if (triangle) {
+ call kodak (device, frames, colors, limit)
+ return
+ }
+
+ # Not standard pseudo color -- do random one
+ # First, set up arrays
+
+ call smark (sp)
+ call salloc (rdata, level*4, TY_SHORT)
+ call salloc (gdata, level*4, TY_SHORT)
+ call salloc (bdata, level*4, TY_SHORT)
+
+ if (seed == -1)
+ seed = level
+
+ call aclrs (Mems[rdata], level*4)
+ call aclrs (Mems[gdata], level*4)
+ call aclrs (Mems[bdata], level*4)
+
+ xfactor = real(GKI_MAXNDC)/level * limit
+
+ # set first data points to zero (0,0) to (1/level,0)
+ Mems[rdata+2] = xfactor
+ Mems[gdata+2] = xfactor
+ Mems[bdata+2] = xfactor
+ # Set last segment to white ((level-1)/level,1.0) to (1.0,1.0)
+ Mems[rdata+level*4-4] = real(level-1) * xfactor
+ Mems[gdata+level*4-4] = real(level-1) * xfactor
+ Mems[bdata+level*4-4] = real(level-1) * xfactor
+ Mems[rdata+level*4-3] = GKI_MAXNDC
+ Mems[gdata+level*4-3] = GKI_MAXNDC
+ Mems[bdata+level*4-3] = GKI_MAXNDC
+ Mems[rdata+level*4-2] = GKI_MAXNDC
+ Mems[gdata+level*4-2] = GKI_MAXNDC
+ Mems[bdata+level*4-2] = GKI_MAXNDC
+ Mems[rdata+level*4-1] = GKI_MAXNDC
+ Mems[gdata+level*4-1] = GKI_MAXNDC
+ Mems[bdata+level*4-1] = GKI_MAXNDC
+
+ # Do the intermediate ones
+ do i=2, level-1 {
+ rp = rdata + (i-1)*4
+ gp = gdata + (i-1)*4
+ bp = bdata + (i-1)*4
+ Mems[rp] = real(i-1) * xfactor
+ Mems[gp] = real(i-1) * xfactor
+ Mems[bp] = real(i-1) * xfactor
+ Mems[rp+1] = urand(seed) * GKI_MAXNDC
+ Mems[gp+1] = urand(seed) * GKI_MAXNDC
+ Mems[bp+1] = urand(seed) * GKI_MAXNDC
+ Mems[rp+2] = real(i) * xfactor
+ Mems[gp+2] = real(i) * xfactor
+ Mems[bp+2] = real(i) * xfactor
+ Mems[rp+3] = Mems[rp+1]
+ Mems[gp+3] = Mems[gp+1]
+ Mems[bp+3] = Mems[bp+1]
+ }
+
+ # If color requested, do it
+ for ( i = 1; colors[i] != IDS_EOD; i = i + 1 ) {
+ pcolor[1] = colors[i]
+ switch (colors[i]) {
+ case IDS_RED:
+ call cvwlut (device, frames, pcolor, Mems[rdata], level*4)
+
+ case IDS_GREEN:
+ call cvwlut (device, frames, pcolor, Mems[gdata], level*4)
+
+ case IDS_BLUE:
+ call cvwlut (device, frames, pcolor, Mems[bdata], level*4)
+ }
+ }
+
+ call sfree (sp)
+end
+
+# KODAK -- provides three variable width and variable center triangular
+# color mapping functions.
+
+procedure kodak (device, frames, colors, limit)
+
+int device # IDS_FRAME_LUT or IDS_OUTPUT_LUT
+short frames[ARB] # frames to change
+short colors[ARB] # colors to affect
+real limit # factor to apply to limit x range
+
+short wdata[20], pcolor[2]
+real center, width
+int n, ksub(), button, i
+int cv_rdbut(), cv_wtbut()
+
+begin
+ pcolor[2] = IDS_EOD
+ for (i = 1; colors[i] != IDS_EOD; i = i + 1) {
+ pcolor[1] = colors[i]
+ switch (colors[i]) {
+ case IDS_RED:
+ n = ksub (1.0, 0.5, wdata, limit)
+
+ case IDS_GREEN:
+ n = ksub (0.5, 0.5, wdata, limit)
+
+ case IDS_BLUE:
+ n = ksub (0.0, 0.5, wdata, limit)
+ }
+
+ call cvwlut (device, frames, pcolor, wdata, n)
+ }
+
+ button = cv_rdbut() # clear buttons
+ repeat {
+ call eprintf ("Press A, B, C for red, green, blue; D to exit\n")
+ button = cv_wtbut()
+ if (button == 4)
+ break
+ switch (button) {
+ case 1:
+ pcolor[1] = IDS_RED
+
+ case 2:
+ pcolor[1] = IDS_GREEN
+
+ case 3:
+ pcolor[1] = IDS_BLUE
+ }
+
+ # Loop, reading cursor and modifying the display for the
+ # selected color.
+
+ repeat {
+ call cv_rcraw(center, width)
+ width = width * 2. # flatten it
+ n = ksub (center, width, wdata, limit)
+ call cvwlut (device, frames, pcolor, wdata, n)
+ button = cv_rdbut()
+ } until (button != 0)
+ }
+end
+
+# KSUB -- determines data points for a triangular mapping function
+# Returns number of points in data array.
+
+int procedure ksub (center, width, data, limit)
+
+real center, width, limit
+short data[ARB]
+
+int n
+real xs, xe, ys, ye, xscale
+
+include "cv.com"
+
+begin
+ n = 0
+ xscale = GKI_MAXNDC * limit
+ if (width < (1.0/cv_yres))
+ width = 1.0/cv_yres
+
+ if (center > 0.) {
+ xs = center - width
+ if (xs < 0.)
+ xs = 0.
+ else if (xs > 0.) {
+ data[1] = 0.
+ data[2] = 0.
+ n = n + 2
+ }
+ ys = (xs - center)/width + 1.0
+ data[n+1] = xs * xscale
+ data[n+2] = ys * GKI_MAXNDC
+ data[n+3] = center * xscale
+ data[n+4] = GKI_MAXNDC
+ n = n + 4
+ }
+
+ if (center < 1.0) {
+ xe = width + center
+ if (xe > 1.0)
+ xe = 1.0
+ ye = (center - xe)/width + 1.0
+ data[n+1] = center * xscale
+ data[n+2] = GKI_MAXNDC
+ data[n+3] = xe * xscale
+ data[n+4] = ye * GKI_MAXNDC
+ n = n + 4
+ if (xe < 1.0) {
+ data[n+1] = xscale
+ data[n+2] = 0
+ n = n + 2
+ }
+ }
+
+ # Extend last value to end
+ if (limit != 1.0) {
+ data[n+1] = GKI_MAXNDC
+ data[n+2] = data[n]
+ n = n + 2
+ }
+
+ return (n)
+end
diff --git a/pkg/images/tv/iis/src/match.x b/pkg/images/tv/iis/src/match.x
new file mode 100644
index 00000000..ebbe523d
--- /dev/null
+++ b/pkg/images/tv/iis/src/match.x
@@ -0,0 +1,172 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include "../lib/ids.h"
+
+# MATCH -- Match look up tables. The command reads
+# match this_one (to) that one
+
+procedure match
+
+char token[SZ_LINE]
+int tok
+short f_ref[2]
+short c_ref[IDS_MAXGCOLOR+1]
+short frames[IDS_MAXIMPL+1]
+short colors[IDS_MAXGCOLOR+1]
+short nextcolor
+int nchar, i, val, ctoi()
+int ltype
+
+include "cv.com"
+
+begin
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if ( (tok == TOK_IDENTIFIER) && (token[1] == 'o') ) {
+ ltype = IDS_OUTPUT_LUT
+ } else {
+ ltype = IDS_FRAME_LUT
+ # "Push back" the token
+ call reset_scan
+ call gargtok (tok, token, SZ_LINE)
+ }
+
+ # All this parsing tells us why YACC and LEX were invented
+ # Use "i" to tell if have parsed something useful
+
+ i = -1
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if ((tok == TOK_IDENTIFIER) && (token[1] == 'f')) {
+ i = 1
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (tok == TOK_NUMBER) {
+ i = 1
+ nchar = ctoi (token, i, val)
+ if ((val < 1) || (val > cv_maxframes)) {
+ call eprintf ("Invalid frame specification: %d\n")
+ call pargi (val)
+ return
+ } else {
+ frames[1] = val
+ frames[2] = IDS_EOD
+ }
+ } else if (ltype == IDS_FRAME_LUT) {
+ call eprintf ("missing frame arguement\n")
+ return
+ } else
+ frames[1] = IDS_EOD
+
+ # default first color argument to all colors for both FRAME and OUTPUT
+ # tables...means make all colors the same.
+
+ colors[1] = IDS_EOD # default all colors
+
+ # Advance if previous token was useful
+
+ if ( i != -1 ) {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+
+ # Look for a color
+
+ if ((tok == TOK_IDENTIFIER) && (token[1] == 'c')) {
+ call cv_color (token[2], colors)
+ if (colors[1] == ERR)
+ return
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+
+ # look for fill word "to"
+
+ if ((tok == TOK_IDENTIFIER) && (token[1] == 't')) {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+
+ # if FRAME LUT, we default frame to first frame to be changed.
+ # if OUTPUT LUT, frame is irrelevant
+
+ i = -1
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'f')
+ i = 2
+ else if (token[1] != 'c') {
+ call eprintf ("Unexpected argument: %s\n")
+ call pargstr (token)
+ return
+ }
+ } else if (tok == TOK_NUMBER)
+ i = 1
+
+ # if ltype is OUTPUT lut, don't care about frame type, but can't
+ # omit it...so default to EOD
+
+ f_ref[1] = IDS_EOD
+ f_ref[2] = IDS_EOD
+ if (ltype == IDS_FRAME_LUT) {
+ if (i == -1) {
+ f_ref[1] = frames[1]
+ } else {
+ nchar = ctoi (token, i, val)
+ if ((val < 1) || (val > cv_maxframes)) {
+ call eprintf ("Invalid frame specification: %d\n")
+ call pargi (val)
+ return
+ }
+ f_ref[1] = val
+ }
+ }
+
+ # Only thing left should be the reference color.
+ # If found a frame before, advance the token.
+
+ if (i != -1) {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ }
+ if ((tok != TOK_NEWLINE) && (tok != TOK_IDENTIFIER)) {
+ call eprintf ("Unexpected input: %s\n")
+ call pargstr (token)
+ return
+ }
+ c_ref[1] = IDS_EOD
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] != 'c') {
+ call eprintf ("Unexpected input (color required): %s\n")
+ call pargstr (token)
+ return
+ } else {
+ call cv_color (token[2], c_ref)
+ if (c_ref[1] == ERR)
+ return
+ }
+ }
+
+ if (c_ref[1] != IDS_EOD)
+ call cvmatch (ltype, f_ref, c_ref, frames, colors)
+ else {
+ # No specific color for reference. If no color specified
+ # to copy into, do all.
+ c_ref[2] = IDS_EOD
+ if ( colors[1] == IDS_EOD ) {
+ colors[1] = IDS_RED
+ colors[2] = IDS_GREEN
+ colors[3] = IDS_BLUE
+ colors[4] = IDS_EOD
+ }
+ # Match for each color given in "colors"
+ for ( i = 1 ; colors[i] != IDS_EOD; i = i + 1) {
+ nextcolor = colors[i+1]
+ colors[i+1] = IDS_EOD
+ c_ref[1] = colors[i]
+ call cvmatch (ltype, f_ref, c_ref, frames, colors[i])
+ colors[i+1] = nextcolor
+ }
+ }
+end
diff --git a/pkg/images/tv/iis/src/maxmin.x b/pkg/images/tv/iis/src/maxmin.x
new file mode 100644
index 00000000..d16874e9
--- /dev/null
+++ b/pkg/images/tv/iis/src/maxmin.x
@@ -0,0 +1,52 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <imhdr.h>
+
+# MAXMIN -- Get the minimum and maximum pixel values of an image. If valid
+# header values are available they are used, otherwise the image is sampled
+# on an even grid and the min and max values of this sample are returned.
+
+procedure maxmin (im, zmin, zmax, nsample_lines)
+
+pointer im
+real zmin, zmax # min and max intensity values
+int nsample_lines # amount of image to sample
+
+int step, ncols, nlines, sample_size, imlines, i
+real minval, maxval
+pointer imgl2r()
+
+begin
+ # Only calculate minimum, maximum pixel values if the current
+ # values are unknown, or if the image was modified since the
+ # old values were computed.
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+
+ if (IM_LIMTIME(im) >= IM_MTIME(im)) {
+ # Use min and max values in image header if they are up to date.
+ zmin = IM_MIN(im)
+ zmax = IM_MAX(im)
+
+ } else {
+ zmin = MAX_REAL
+ zmax = -MAX_REAL
+
+ # Try to include a constant number of pixels in the sample
+ # regardless of the image size. The entire image is used if we
+ # have a small image, and at least sample_lines lines are read
+ # if we have a large image.
+
+ sample_size = 512 * nsample_lines
+ imlines = min(nlines, max(nsample_lines, sample_size / ncols))
+ step = nlines / (imlines + 1)
+
+ do i = 1 + step, nlines, max (1, step) {
+ call alimr (Memr[imgl2r(im,i)], ncols, minval, maxval)
+ zmin = min (zmin, minval)
+ zmax = max (zmax, maxval)
+ }
+ }
+end
diff --git a/pkg/images/tv/iis/src/mkpkg b/pkg/images/tv/iis/src/mkpkg
new file mode 100644
index 00000000..34ee515c
--- /dev/null
+++ b/pkg/images/tv/iis/src/mkpkg
@@ -0,0 +1,39 @@
+# Make the CV display load and control package.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ blink.x ../lib/ids.h <ctotok.h> <ctype.h> <gki.h> cv.com
+ clear.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ cv.x cv.com cv.h ../lib/ids.h <ctotok.h> <error.h> <fio.h>\
+ <fset.h> <gki.h>
+ cvparse.x cv.com ../lib/ids.h <ctype.h>
+ cvulut.x cv.h <ctype.h> <error.h>
+ cvutil.x cv.com cv.h ../lib/ids.h <gki.h> <gset.h> <imhdr.h>\
+ cv.com
+ display.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ load1.x cv.com cv.h ../lib/ids.h <error.h> <gki.h> gwindow.h\
+ <fio.h> <fset.h> <imhdr.h> <imset.h> <mach.h>
+ load2.x cv.com cv.h ../lib/ids.h <error.h> <gki.h> gwindow.h\
+ cv.com <fio.h> <fset.h> <imhdr.h> <imset.h> <mach.h>
+ map.x ../lib/ids.h <ctotok.h> <ctype.h> <gki.h> cv.com
+ match.x ../lib/ids.h <ctotok.h> cv.com
+ maxmin.x <imhdr.h> <mach.h>
+ offset.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ pan.x cv.com ../lib/ids.h <ctotok.h> <ctype.h> <gki.h>
+ range.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ rdcur.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com <gki.h>
+ reset.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ sigl2.x <error.h> <imhdr.h>
+ snap.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com <gki.h>\
+ <imhdr.h>
+ split.x ../lib/ids.h <ctotok.h> <ctype.h> cv.com
+ tell.x ../lib/ids.h cv.com
+ text.x ../lib/ids.h <ctotok.h> <ctype.h>
+ window.x ../lib/ids.h <ctotok.h> <ctype.h> <gki.h> cv.com
+ zoom.x ../lib/ids.h <ctotok.h> <ctype.h> <gki.h> cv.com
+ zscale.x <imhdr.h>
+ ;
diff --git a/pkg/images/tv/iis/src/offset.x b/pkg/images/tv/iis/src/offset.x
new file mode 100644
index 00000000..356ae55f
--- /dev/null
+++ b/pkg/images/tv/iis/src/offset.x
@@ -0,0 +1,53 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# OFFSET -- Change the bias (offset) for certain colors
+
+procedure offset()
+
+int tok, i, nchar, ip
+char token[SZ_LINE]
+short color[IDS_MAXGCOLOR+1]
+short offsetdata[4] # extra space for cvmove EOD
+int count, ctoi()
+
+include "cv.com"
+
+begin
+ # In principle, we should be able to accept input for color group
+ # followed by offset value(s) or "vice versa" or for a series of
+ # color/offset pairs. We try for most of that.
+ color[1] = ERR
+ offsetdata[1] = ERR
+ count = 1
+ # anything but TOK_NEWLINE
+ tok = TOK_NUMBER
+ repeat {
+ if (tok == TOK_NEWLINE) {
+ call eprintf ("Insufficient offset specification\n")
+ return
+ }
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (token[1] == 'c') {
+ call cv_color (token[2], color)
+ if (color[1] == ERR)
+ return
+ } else if (tok == TOK_NUMBER) {
+ ip = 1
+ nchar = ctoi (token, ip, i)
+ if ( count <= 3) {
+ offsetdata[count] = i
+ count = count + 1
+ }
+ }
+ } until ( (color[1] != ERR) && (offsetdata[1] != ERR) &&
+ (tok == TOK_NEWLINE) )
+
+ offsetdata[count] = IDS_EOD # mark end
+
+ call cvoffset (color, offsetdata)
+end
diff --git a/pkg/images/tv/iis/src/pan.x b/pkg/images/tv/iis/src/pan.x
new file mode 100644
index 00000000..b8929510
--- /dev/null
+++ b/pkg/images/tv/iis/src/pan.x
@@ -0,0 +1,99 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# PAN -- pan some or all of the frames
+
+procedure pan()
+
+char token[SZ_LINE]
+int tok
+short frames[IDS_MAXIMPL+2] # frames, graphics, EOD
+
+include "cv.com"
+
+begin
+ frames[1] = IDS_EOD # default all frames
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (token[1] == 'f') {
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (tok == TOK_NUMBER) {
+ call cv_frame (token[1], frames)
+ if (frames[1] == ERR)
+ return
+ } else {
+ call eprintf ("Unexpected input: %s\n")
+ call pargstr (token)
+ return
+ }
+
+ call pansub (frames)
+end
+
+
+# PANSUB -- Pan subroutine, handles code common to pan and zoom
+
+procedure pansub (frames)
+
+short frames[ARB] # frames to pan
+
+int button
+int cnum, cv_rdbut()
+real x,y, xc, yc
+real oldx, oldy
+
+include "cv.com"
+
+begin
+ button = cv_rdbut() # clear buttons by reading them
+ call eprintf ("Press any button when done\n")
+
+ # Where is cursor now?
+
+ call cv_rcraw (xc,yc)
+
+ # Calculate NDC screen center and cursor number.
+ # x,y are NDC, but always < 1.0 The transformation applied here
+ # insures that the correct pixel is calculated by the kernel
+ # after passing x,y through the gio cursor routines.
+ x = real(cv_xcen - 1) * cv_xcon / GKI_MAXNDC
+ y = real(cv_ycen - 1) * cv_ycon / GKI_MAXNDC
+ cnum = frames[1]
+ if (cnum == IDS_EOD)
+ cnum = 0
+ call cv_scraw (x, y) # put cursor at screen center
+
+ # Determine NDC there for frame of interest
+ call cv_rcur (cnum, x, y)
+
+ # Restore cursor
+ call cv_scraw (xc, yc)
+
+ repeat {
+ oldx = xc
+ oldy = yc
+ repeat {
+ call cv_rcraw (xc, yc)
+ button = cv_rdbut()
+ } until ( (xc != oldx) || (yc != oldy) || (button > 0))
+ # Determine change and reflect it about current screen
+ # center so image moves in direction cursor moves.
+ x = x - (xc - oldx)
+ y = y - (yc - oldy)
+ if (x > 1.0)
+ x = x - 1.0
+ else if (x < 0)
+ x = x + 1.0
+ if (y > 1.0)
+ y = y - 1.0
+ else if (y < 0)
+ y = y + 1.0
+ call cvpan (frames, x, y)
+ } until (button > 0)
+end
diff --git a/pkg/images/tv/iis/src/range.x b/pkg/images/tv/iis/src/range.x
new file mode 100644
index 00000000..664e3ab8
--- /dev/null
+++ b/pkg/images/tv/iis/src/range.x
@@ -0,0 +1,57 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# RANGE -- set the scaling (range) registers
+
+procedure range()
+
+char token[SZ_LINE]
+int tok, i, nchar, ip
+short color[IDS_MAXGCOLOR+1]
+short rdata[4] # extra space for cvmove EOD
+int count, ctoi()
+
+include "cv.com"
+
+begin
+ # In principle, we should be able to accept input for color group
+ # followed by range value(s) or "vice versa" or for a series of
+ # color/range pairs. We try for most of that.
+ color[1] = IDS_EOD
+ rdata[1] = ERR
+ count = 1
+ # anything but TOK_NEWLINE
+ tok = TOK_NUMBER
+ repeat {
+ if (tok == TOK_NEWLINE) {
+ call eprintf ("Insufficient range specification\n")
+ return
+ }
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (token[1] == 'c') {
+ call cv_color (token[2], color)
+ if (color[1] == ERR)
+ return
+ } else if (tok == TOK_NUMBER) {
+ ip = 1
+ nchar = ctoi (token, ip, i)
+ if (i < 1) {
+ call eprintf ("bad range specification: %d\n")
+ call pargi (i)
+ return
+ }
+ if ( count <= 3) {
+ rdata[count] = i
+ count = count + 1
+ }
+ }
+ } until ( (rdata[1] != ERR) && (tok == TOK_NEWLINE ))
+
+ rdata[count] = IDS_EOD # mark end
+
+ call cvrange ( color, rdata)
+end
diff --git a/pkg/images/tv/iis/src/rdcur.x b/pkg/images/tv/iis/src/rdcur.x
new file mode 100644
index 00000000..5d27097e
--- /dev/null
+++ b/pkg/images/tv/iis/src/rdcur.x
@@ -0,0 +1,111 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# RDCUR -- read cursor and datum
+
+procedure rdcur()
+
+char token[SZ_LINE], ch
+int tok, cnum, px, py
+int junk, ip, fx, fy
+real x,y
+short datum
+short frames[IDS_MAXIMPL+2] # frames, one graphics, EOD
+int scan(), ctoi(), mod(), and()
+
+include "cv.com"
+
+begin
+ cnum = ERR
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_NUMBER) {
+ ip = 1
+ junk = ctoi (token, ip, cnum)
+ frames[1] = cnum
+ frames[2] = IDS_EOD
+ }
+ else if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'o') {
+ if (token[2] == 'n')
+ call cvcur(IDS_ON)
+ else if (token[2] == 'f')
+ call cvcur(IDS_OFF)
+ else {
+ call eprintf ("Unrecognized cursor command: %s\n")
+ call pargstr (token)
+ }
+ return
+ }
+ call cv_frame (token[2], frames)
+ cnum = frames[1]
+ if ( cnum == IDS_EOD) {
+ call eprintf ("Please specify a particular frame\n")
+ return
+ }
+ }
+ if ( (cnum == ERR) || (cnum < 1) ) {
+ call eprintf ("bad cursor number: %d\n")
+ call pargi (cnum)
+ return
+ }
+
+ # set kernel to do i/o on specified frames (for ggcell routine)
+ call cv_iset (frames)
+
+ call eprintf ("Press <cr> for each read; any key but <sp>, and then <cr>, to exit\n")
+ repeat {
+ if (scan() != EOS)
+ break
+ repeat {
+ call scanc (ch)
+ } until (ch != ' ')
+ if (ch != '\n')
+ break
+ call cv_rcur (cnum, x, y)
+ call ggcell (cv_gp, datum, 1, 1, x, y, x, y)
+ x = x * GKI_MAXNDC / cv_xcon + 1.
+ y = y * GKI_MAXNDC / cv_ycon + 1.
+ px = int(x)
+ py = int(y)
+ # Only allow fractions to 1/8 as that is max zoom for IIS
+ x = real (int((x - px)*8))/8.
+ y = real (int((y - py)*8))/8.
+ # Print minimum number of decimal places, but do x and y the same
+ call eprintf ("frame %d, pixel (")
+ call pargi (cnum)
+ fx = x * 8
+ fy = y * 8
+ if ((fx == 0) && (fy == 0)) {
+ call eprintf ("%d,%d")
+ call pargi (px)
+ call pargi (py)
+ junk = 0
+ } else {
+ call eprintf ("%.*f,%.*f")
+
+ if ( (mod(fx,4) == 0) && (mod(fy,4) == 0) )
+ junk = 1
+ else if ( (and(fx,1) != 0) || (and(fy,1) != 0) )
+ junk = 3
+ else
+ junk = 2
+
+ call pargi (junk)
+ call pargr (px+x)
+ call pargi (junk)
+ call pargr (py+y)
+ }
+ if (junk == 0)
+ junk = 8
+ else
+ junk = 6 - 2 * junk
+ call eprintf ("): %*w%4d\n")
+ call pargi (junk)
+ call pargs (datum)
+ }
+end
diff --git a/pkg/images/tv/iis/src/reset.x b/pkg/images/tv/iis/src/reset.x
new file mode 100644
index 00000000..3a2e60e9
--- /dev/null
+++ b/pkg/images/tv/iis/src/reset.x
@@ -0,0 +1,37 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# RESET -- reset the display
+
+procedure reset()
+
+char token[SZ_LINE]
+int tok
+
+include "cv.com"
+
+begin
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ switch(token[1]) {
+ case 'r':
+ call cvreset( IDS_R_SOFT)
+
+ case 't':
+ call cvreset( IDS_R_MEDIUM)
+
+ case 'i':
+ call cvreset( IDS_R_HARD)
+
+ case 'a':
+ call cvreset( IDS_R_SOFT)
+ call cvreset( IDS_R_MEDIUM)
+ call cvreset( IDS_R_HARD)
+
+ }
+ }
+end
diff --git a/pkg/images/tv/iis/src/sigl2.x b/pkg/images/tv/iis/src/sigl2.x
new file mode 100644
index 00000000..226d4f5b
--- /dev/null
+++ b/pkg/images/tv/iis/src/sigl2.x
@@ -0,0 +1,677 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <error.h>
+
+.help sigl2, sigl2_setup
+.nf ___________________________________________________________________________
+SIGL2 -- Get a line from a spatially scaled 2-dimensional image. This procedure
+works like the regular IMIO get line procedure, but rescales the input
+2-dimensional image in either or both axes upon input. If the magnification
+ratio required is greater than 0 and less than 2 then linear interpolation is
+used to resample the image. If the magnification ratio is greater than or
+equal to 2 then the image is block averaged by the smallest factor which
+reduces the magnification to the range 0-2 and then interpolated back up to
+the desired size. In some cases this will smooth the data slightly, but the
+operation is efficient and avoids aliasing effects.
+
+ si = sigl2_setup (im, x1,x2,nx, y1,y2,ny)
+ sigl2_free (si)
+ ptr = sigl2[sr] (si, linenumber)
+
+SIGL2_SETUP must be called to set up the transformations after mapping the
+image and before performing any scaled i/o to the image. SIGL2_FREE must be
+called when finished to return buffer space.
+.endhelp ______________________________________________________________________
+
+# Scaled image descriptor for 2-dim images
+
+define SI_LEN 15
+define SI_MAXDIM 2 # images of 2 dimensions supported
+define SI_NBUFS 3 # nbuffers used by SIGL2
+
+define SI_IM Memi[$1] # pointer to input image header
+define SI_GRID Memi[$1+1+$2-1] # pointer to array of X coords
+define SI_NPIX Memi[$1+3+$2-1] # number of X coords
+define SI_BAVG Memi[$1+5+$2-1] # X block averaging factor
+define SI_INTERP Memi[$1+7+$2-1] # interpolate X axis
+define SI_BUF Memi[$1+9+$2-1] # line buffers
+define SI_TYBUF Memi[$1+12] # buffer type
+define SI_XOFF Memi[$1+13] # offset in input image to first X
+define SI_INIT Memi[$1+14] # YES until first i/o is done
+
+define OUTBUF SI_BUF($1,3)
+
+define SI_TOL (1E-5) # close to a pixel
+define INTVAL (abs ($1 - nint($1)) < SI_TOL)
+define SWAPI {tempi=$2;$2=$1;$1=tempi}
+define SWAPP {tempp=$2;$2=$1;$1=tempp}
+define NOTSET (-9999)
+
+# SIGL2_SETUP -- Set up the spatial transformation for SIGL2[SR]. Compute
+# the block averaging factors (1 if no block averaging is required) and
+# the sampling grid points, i.e., pixel coordinates of the output pixels in
+# the input image.
+#
+# Valdes - Jan 9, 1985:
+# Nx or ny can be 1 and blocking factors can be specified.
+
+pointer procedure sigl2_setup (im, px1, px2, nx, xblk, py1, py2, ny, yblk)
+
+pointer im # the input image
+real px1, px2 # range in X to be sampled on an even grid
+int nx # number of output pixels in X
+int xblk # blocking factor in x
+real py1, py2 # range in Y to be sampled on an even grid
+int ny # number of output pixels in Y
+int yblk # blocking factor in y
+
+int npix, noldpix, nbavpix, i, j
+int npts[SI_MAXDIM] # number of output points for axis
+int blksize[SI_MAXDIM] # block averaging factor (npix per block)
+real tau[SI_MAXDIM] # tau = p(i+1) - p(i) in fractional pixels
+real p1[SI_MAXDIM] # starting pixel coords in each axis
+real p2[SI_MAXDIM] # ending pixel coords in each axis
+real scalar, start
+pointer si, gp
+
+begin
+ iferr (call calloc (si, SI_LEN, TY_STRUCT))
+ call erract (EA_FATAL)
+
+ SI_IM(si) = im
+ SI_NPIX(si,1) = nx
+ SI_NPIX(si,2) = ny
+ SI_INIT(si) = YES
+
+ p1[1] = px1 # X = index 1
+ p2[1] = px2
+ npts[1] = nx
+ blksize[1] = xblk
+
+ p1[2] = py1 # Y = index 2
+ p2[2] = py2
+ npts[2] = ny
+ blksize[2] = yblk
+
+ # Compute block averaging factors if not defined.
+ # If there is only one pixel then the block average is the average
+ # between the first and last point.
+
+ do i = 1, SI_MAXDIM {
+ if ((blksize[i] >= 1) && !IS_INDEFI (blksize[i])) {
+ if (npts[i] == 1)
+ tau[i] = 0.
+ else
+ tau[i] = (p2[i] - p1[i]) / (npts[i] - 1)
+ } else {
+ if (npts[i] == 1) {
+ tau[i] = 0.
+ blksize[i] = int (p2[i] - p1[i] + 1)
+ } else {
+ tau[i] = (p2[i] - p1[i]) / (npts[i] - 1)
+ if (tau[i] >= 2.0) {
+
+ # If nx or ny is not an integral multiple of the block
+ # averaging factor, noldpix is the next larger number
+ # which is an integral multiple. When the image is
+ # block averaged pixels will be replicated as necessary
+ # to fill the last block out to this size.
+
+ blksize[i] = int (tau[i])
+ npix = p2[i] - p1[i] + 1
+ noldpix = (npix+blksize[i]-1) / blksize[i] * blksize[i]
+ nbavpix = noldpix / blksize[i]
+ scalar = real (nbavpix - 1) / real (noldpix - 1)
+ p1[i] = (p1[i] - 1.0) * scalar + 1.0
+ p2[i] = (p2[i] - 1.0) * scalar + 1.0
+ tau[i] = (p2[i] - p1[i]) / (npts[i] - 1)
+ } else
+ blksize[i] = 1
+ }
+ }
+ }
+
+ SI_BAVG(si,1) = blksize[1]
+ SI_BAVG(si,2) = blksize[2]
+
+ if (IS_INDEFI (xblk))
+ xblk = blksize[1]
+ if (IS_INDEFI (yblk))
+ yblk = blksize[2]
+
+ # Allocate and initialize the grid arrays, specifying the X and Y
+ # coordinates of each pixel in the output image, in units of pixels
+ # in the input (possibly block averaged) image.
+
+ do i = 1, SI_MAXDIM {
+ # The X coordinate is special. We do not want to read entire
+ # input image lines if only a range of input X values are needed.
+ # Since the X grid vector passed to ALUI (the interpolator) must
+ # contain explicit offsets into the vector being interpolated,
+ # we must generate interpolator grid points starting near 1.0.
+ # The X origin, used to read the block averaged input line, is
+ # given by XOFF.
+
+ if (i == 1) {
+ SI_XOFF(si) = int (p1[i])
+ start = p1[1] - int (p1[i]) + 1.0
+ } else
+ start = p1[i]
+
+ # Do the axes need to be interpolated?
+ if (INTVAL(start) && INTVAL(tau[i]))
+ SI_INTERP(si,i) = NO
+ else
+ SI_INTERP(si,i) = YES
+
+ # Allocate grid buffer and set the grid points.
+ iferr (call malloc (gp, npts[i], TY_REAL))
+ call erract (EA_FATAL)
+ SI_GRID(si,i) = gp
+ do j = 0, npts[i]-1
+ Memr[gp+j] = start + (j * tau[i])
+ }
+
+ return (si)
+end
+
+
+# SIGL2_FREE -- Free storage associated with an image opened for scaled
+# input. This does not close and unmap the image.
+
+procedure sigl2_free (si)
+
+pointer si
+int i
+
+begin
+ # Free SIGL2 buffers.
+ do i = 1, SI_NBUFS
+ if (SI_BUF(si,i) != NULL)
+ call mfree (SI_BUF(si,i), SI_TYBUF(si))
+
+ # Free GRID buffers.
+ do i = 1, SI_MAXDIM
+ if (SI_GRID(si,i) != NULL)
+ call mfree (SI_GRID(si,i), TY_REAL)
+
+ call mfree (si, TY_STRUCT)
+end
+
+
+# SIGL2S -- Get a line of type short from a scaled image. Block averaging is
+# done by a subprocedure; this procedure gets a line from a possibly block
+# averaged image and if necessary interpolates it to the grid points of the
+# output line.
+
+pointer procedure sigl2s (si, lineno)
+
+pointer si # pointer to SI descriptor
+int lineno
+
+pointer rawline, tempp, gp
+int i, buf_y[2], new_y[2], tempi, curbuf, altbuf
+int npix, nblks_y, ybavg, x1, x2
+real x, y, weight_1, weight_2
+pointer si_blkavgs()
+errchk si_blkavgs
+
+begin
+ npix = SI_NPIX(si,1)
+
+ # Determine the range of X (in pixels on the block averaged input image)
+ # required for the interpolator.
+
+ gp = SI_GRID(si,1)
+ x1 = SI_XOFF(si)
+ x = Memr[gp+npix-1]
+ x2 = x1 + int(x)
+ if (INTVAL(x))
+ x2 = x2 - 1
+ x2 = max (x1 + 1, x2)
+
+ gp = SI_GRID(si,2)
+ y = Memr[gp+lineno-1]
+
+ # The following is an optimization provided for the case when it is
+ # not necessary to interpolate in either X or Y. Block averaging is
+ # permitted.
+
+ if (SI_INTERP(si,1) == NO && SI_INTERP(si,2) == NO)
+ return (si_blkavgs (SI_IM(si), x1, x2, int(y),
+ SI_BAVG(si,1), SI_BAVG(si,2)))
+
+ # If we are interpolating in Y two buffers are required, one for each
+ # of the two input image lines required to interpolate in Y. The lines
+ # stored in these buffers are interpolated in X to the output grid but
+ # not in Y. Both buffers are not required if we are not interpolating
+ # in Y, but we use them anyhow to simplify the code.
+
+ if (SI_INIT(si) == YES) {
+ do i = 1, 2 {
+ if (SI_BUF(si,i) != NULL)
+ call mfree (SI_BUF(si,i), SI_TYBUF(si))
+ call malloc (SI_BUF(si,i), npix, TY_SHORT)
+ SI_TYBUF(si) = TY_SHORT
+ buf_y[i] = NOTSET
+ }
+ if (OUTBUF(si) != NULL)
+ call mfree (OUTBUF(si), SI_TYBUF(si))
+ call malloc (OUTBUF(si), npix, TY_SHORT)
+ SI_INIT(si) = NO
+ }
+
+ # If the Y value of the new line is not in range of the contents of the
+ # current line buffers, refill one or both buffers. To refill we must
+ # read a (possibly block averaged) input line and interpolate it onto
+ # the X grid. The X and Y values herein are in the coordinate system
+ # of the (possibly block averaged) input image.
+
+ new_y[1] = int(y)
+ new_y[2] = int(y) + 1
+
+ # Get the pair of lines whose integral Y values form an interval
+ # containing the fractional Y value of the output line. Sometimes the
+ # desired line will happen to be in the other buffer already, in which
+ # case we just have to swap buffers. Often the new line will be the
+ # current line, in which case nothing is done. This latter case occurs
+ # frequently when the magnification ratio is large.
+
+ curbuf = 1
+ altbuf = 2
+
+ do i = 1, 2 {
+ if (new_y[i] == buf_y[i]) {
+ ;
+ } else if (new_y[i] == buf_y[altbuf]) {
+ SWAPP (SI_BUF(si,1), SI_BUF(si,2))
+ SWAPI (buf_y[1], buf_y[2])
+
+ } else {
+ # Get line and interpolate onto output grid. If interpolation
+ # is not required merely copy data out. This code is set up
+ # to always use two buffers; in effect, there is one buffer of
+ # look ahead, even when Y[i] is integral. This means that we
+ # will go out of bounds by one line at the top of the image.
+ # This is handled by copying the last line.
+
+ ybavg = SI_BAVG(si,2)
+ nblks_y = (IM_LEN (SI_IM(si), 2) + ybavg-1) / ybavg
+ if (new_y[i] <= nblks_y)
+ rawline = si_blkavgs (SI_IM(si), x1, x2, new_y[i],
+ SI_BAVG(si,1), SI_BAVG(si,2))
+
+ if (SI_INTERP(si,1) == NO)
+ call amovs (Mems[rawline], Mems[SI_BUF(si,i)], npix)
+ else {
+ call aluis (Mems[rawline], Mems[SI_BUF(si,i)],
+ Memr[SI_GRID(si,1)], npix)
+ }
+
+ buf_y[i] = new_y[i]
+ }
+
+ SWAPI (altbuf, curbuf)
+ }
+
+ # We now have two line buffers straddling the output Y value,
+ # interpolated to the X grid of the output line. To complete the
+ # bilinear interpolation operation we take a weighted sum of the two
+ # lines. If the range from buf_y[1] to buf_y[2] is repeatedly
+ # interpolated in Y no additional i/o occurs and the linear
+ # interpolation operation (ALUI) does not have to be repeated (only the
+ # weighted sum is required). If the distance of Y from one of the
+ # buffers is zero then we do not even have to take a weighted sum.
+ # This is not unusual because we may be called with a magnification
+ # of 1.0 in Y.
+
+ weight_1 = 1.0 - (y - buf_y[1])
+ weight_2 = 1.0 - weight_1
+
+ if (weight_2 < SI_TOL)
+ return (SI_BUF(si,1))
+ else if (weight_1 < SI_TOL)
+ return (SI_BUF(si,2))
+ else {
+ call awsus (Mems[SI_BUF(si,1)], Mems[SI_BUF(si,2)],
+ Mems[OUTBUF(si)], npix, weight_1, weight_2)
+ return (OUTBUF(si))
+ }
+end
+
+
+# SI_BLKAVGS -- Get a line from a block averaged image of type short.
+# For example, block averaging by a factor of 2 means that pixels 1 and 2
+# are averaged to produce the first output pixel, 3 and 4 are averaged to
+# produce the second output pixel, and so on. If the length of an axis
+# is not an integral multiple of the block size then the last pixel in the
+# last block will be replicated to fill out the block; the average is still
+# defined even if a block is not full.
+
+pointer procedure si_blkavgs (im, x1, x2, y, xbavg, ybavg)
+
+pointer im # input image
+int x1, x2 # range of x blocks to be read
+int y # y block to be read
+int xbavg, ybavg # X and Y block averaging factors
+
+short temp_s
+int nblks_x, nblks_y, ncols, nlines, xoff, i, j
+int first_line, nlines_in_sum, npix, nfull_blks, count
+real sum
+pointer sp, a, b
+pointer imgs2s()
+errchk imgs2s
+
+begin
+ call smark (sp)
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ xoff = (x1 - 1) * xbavg + 1
+ npix = min (ncols, xoff + (x2 - x1 + 1) * xbavg - 1)
+
+ if ((xbavg < 1) || (ybavg < 1))
+ call error (1, "si_blkavg: illegal block size")
+ else if (x1 < 1 || x2 > ncols)
+ call error (2, "si_blkavg: column index out of bounds")
+ else if ((xbavg == 1) && (ybavg == 1))
+ return (imgs2s (im, xoff, xoff + npix - 1, y, y))
+
+ nblks_x = (npix + xbavg-1) / xbavg
+ nblks_y = (nlines + ybavg-1) / ybavg
+
+ if (y < 1 || y > nblks_y)
+ call error (2, "si_blkavg: block number out of range")
+
+ call salloc (b, nblks_x, TY_SHORT)
+
+ if (ybavg > 1) {
+ call aclrs (Mems[b], nblks_x)
+ nlines_in_sum = 0
+ }
+
+ # Read and accumulate all input lines in the block.
+ first_line = (y - 1) * ybavg + 1
+
+ do i = first_line, min (nlines, first_line + ybavg - 1) {
+ # Get line from input image.
+ a = imgs2s (im, xoff, xoff + npix - 1, i, i)
+
+ # Block average line in X.
+ if (xbavg > 1) {
+ # First block average only the full blocks.
+ nfull_blks = npix / xbavg
+ call abavs (Mems[a], Mems[a], nfull_blks, xbavg)
+
+ # Now average the final partial block, if any.
+ if (nfull_blks < nblks_x) {
+ sum = 0.0
+ count = 0
+ do j = nfull_blks * xbavg + 1, npix {
+ sum = sum + Mems[a+j-1]
+ count = count + 1
+ }
+ Mems[a+nblks_x-1] = sum / count
+ }
+ }
+
+ # Add line into block sum. Keep track of number of lines in sum
+ # so that we can compute block average later.
+ if (ybavg > 1) {
+ call aadds (Mems[a], Mems[b], Mems[b], nblks_x)
+ nlines_in_sum = nlines_in_sum + 1
+ }
+ }
+
+ # Compute the block average in Y from the sum of all lines block
+ # averaged in X. Overwrite buffer A, the buffer returned by IMIO.
+ # This is kosher because the block averaged line is never longer
+ # than an input line.
+
+ if (ybavg > 1) {
+ temp_s = nlines_in_sum
+ call adivks (Mems[b], temp_s, Mems[a], nblks_x)
+ }
+
+ call sfree (sp)
+ return (a)
+end
+
+
+# SIGL2R -- Get a line of type real from a scaled image. Block averaging is
+# done by a subprocedure; this procedure gets a line from a possibly block
+# averaged image and if necessary interpolates it to the grid points of the
+# output line.
+
+pointer procedure sigl2r (si, lineno)
+
+pointer si # pointer to SI descriptor
+int lineno
+
+pointer rawline, tempp, gp
+int i, buf_y[2], new_y[2], tempi, curbuf, altbuf
+int npix, nblks_y, ybavg, x1, x2
+real x, y, weight_1, weight_2
+pointer si_blkavgr()
+errchk si_blkavgr
+
+begin
+ npix = SI_NPIX(si,1)
+
+ # Deterine the range of X (in pixels on the block averaged input image)
+ # required for the interpolator.
+
+ gp = SI_GRID(si,1)
+ x1 = SI_XOFF(si)
+ x = Memr[gp+npix-1]
+ x2 = x1 + int(x)
+ if (INTVAL(x))
+ x2 = x2 - 1
+ x2 = max (x1 + 1, x2)
+
+ gp = SI_GRID(si,2)
+ y = Memr[gp+lineno-1]
+
+ # The following is an optimization provided for the case when it is
+ # not necessary to interpolate in either X or Y. Block averaging is
+ # permitted.
+
+ if (SI_INTERP(si,1) == NO && SI_INTERP(si,2) == NO)
+ return (si_blkavgr (SI_IM(si), x1, x2, int(y),
+ SI_BAVG(si,1), SI_BAVG(si,2)))
+
+ # If we are interpolating in Y two buffers are required, one for each
+ # of the two input image lines required to interpolate in Y. The lines
+ # stored in these buffers are interpolated in X to the output grid but
+ # not in Y. Both buffers are not required if we are not interpolating
+ # in Y, but we use them anyhow to simplify the code.
+
+ if (SI_INIT(si) == YES) {
+ do i = 1, 2 {
+ if (SI_BUF(si,i) != NULL)
+ call mfree (SI_BUF(si,i), SI_TYBUF(si))
+ call malloc (SI_BUF(si,i), npix, TY_REAL)
+ SI_TYBUF(si) = TY_REAL
+ buf_y[i] = NOTSET
+ }
+ if (OUTBUF(si) != NULL)
+ call mfree (OUTBUF(si), SI_TYBUF(si))
+ call malloc (OUTBUF(si), npix, TY_REAL)
+ SI_INIT(si) = NO
+ }
+
+ # If the Y value of the new line is not in range of the contents of the
+ # current line buffers, refill one or both buffers. To refill we must
+ # read a (possibly block averaged) input line and interpolate it onto
+ # the X grid. The X and Y values herein are in the coordinate system
+ # of the (possibly block averaged) input image.
+
+ new_y[1] = int(y)
+ new_y[2] = int(y) + 1
+
+ # Get the pair of lines whose integral Y values form an interval
+ # containing the fractional Y value of the output line. Sometimes the
+ # desired line will happen to be in the other buffer already, in which
+ # case we just have to swap buffers. Often the new line will be the
+ # current line, in which case nothing is done. This latter case occurs
+ # frequently when the magnification ratio is large.
+
+ curbuf = 1
+ altbuf = 2
+
+ do i = 1, 2 {
+ if (new_y[i] == buf_y[i]) {
+ ;
+ } else if (new_y[i] == buf_y[altbuf]) {
+ SWAPP (SI_BUF(si,1), SI_BUF(si,2))
+ SWAPI (buf_y[1], buf_y[2])
+
+ } else {
+ # Get line and interpolate onto output grid. If interpolation
+ # is not required merely copy data out. This code is set up
+ # to always use two buffers; in effect, there is one buffer of
+ # look ahead, even when Y[i] is integral. This means that we
+ # will go out of bounds by one line at the top of the image.
+ # This is handled by copying the last line.
+
+ ybavg = SI_BAVG(si,2)
+ nblks_y = (IM_LEN (SI_IM(si), 2) + ybavg-1) / ybavg
+ if (new_y[i] <= nblks_y)
+ rawline = si_blkavgr (SI_IM(si), x1, x2, new_y[i],
+ SI_BAVG(si,1), SI_BAVG(si,2))
+
+ if (SI_INTERP(si,1) == NO)
+ call amovr (Memr[rawline], Memr[SI_BUF(si,i)], npix)
+ else {
+ call aluir (Memr[rawline], Memr[SI_BUF(si,i)],
+ Memr[SI_GRID(si,1)], npix)
+ }
+
+ buf_y[i] = new_y[i]
+ }
+
+ SWAPI (altbuf, curbuf)
+ }
+
+ # We now have two line buffers straddling the output Y value,
+ # interpolated to the X grid of the output line. To complete the
+ # bilinear interpolation operation we take a weighted sum of the two
+ # lines. If the range from buf_y[1] to buf_y[2] is repeatedly
+ # interpolated in Y no additional i/o occurs and the linear
+ # interpolation operation (ALUI) does not have to be repeated (only the
+ # weighted sum is required). If the distance of Y from one of the
+ # buffers is zero then we do not even have to take a weighted sum.
+ # This is not unusual because we may be called with a magnification
+ # of 1.0 in Y.
+
+ weight_1 = 1.0 - (y - buf_y[1])
+ weight_2 = 1.0 - weight_1
+
+ if (weight_2 < SI_TOL)
+ return (SI_BUF(si,1))
+ else if (weight_1 < SI_TOL)
+ return (SI_BUF(si,2))
+ else {
+ call awsur (Memr[SI_BUF(si,1)], Memr[SI_BUF(si,2)],
+ Memr[OUTBUF(si)], npix, weight_1, weight_2)
+ return (OUTBUF(si))
+ }
+end
+
+
+# SI_BLKAVGR -- Get a line from a block averaged image of type short.
+# For example, block averaging by a factor of 2 means that pixels 1 and 2
+# are averaged to produce the first output pixel, 3 and 4 are averaged to
+# produce the second output pixel, and so on. If the length of an axis
+# is not an integral multiple of the block size then the last pixel in the
+# last block will be replicated to fill out the block; the average is still
+# defined even if a block is not full.
+
+pointer procedure si_blkavgr (im, x1, x2, y, xbavg, ybavg)
+
+pointer im # input image
+int x1, x2 # range of x blocks to be read
+int y # y block to be read
+int xbavg, ybavg # X and Y block averaging factors
+
+int nblks_x, nblks_y, ncols, nlines, xoff, i, j
+int first_line, nlines_in_sum, npix, nfull_blks, count
+real sum
+pointer sp, a, b
+pointer imgs2r()
+errchk imgs2r
+
+begin
+ call smark (sp)
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ xoff = (x1 - 1) * xbavg + 1
+ npix = min (ncols, xoff + (x2 - x1 + 1) * xbavg - 1)
+
+ if ((xbavg < 1) || (ybavg < 1))
+ call error (1, "si_blkavg: illegal block size")
+ else if (x1 < 1 || x2 > ncols)
+ call error (2, "si_blkavg: column index out of bounds")
+ else if ((xbavg == 1) && (ybavg == 1))
+ return (imgs2r (im, xoff, xoff + npix - 1, y, y))
+
+ nblks_x = (npix + xbavg-1) / xbavg
+ nblks_y = (nlines + ybavg-1) / ybavg
+
+ if (y < 1 || y > nblks_y)
+ call error (2, "si_blkavg: block number out of range")
+
+ call salloc (b, nblks_x, TY_REAL)
+
+ if (ybavg > 1) {
+ call aclrr (Memr[b], nblks_x)
+ nlines_in_sum = 0
+ }
+
+ # Read and accumulate all input lines in the block.
+ first_line = (y - 1) * ybavg + 1
+
+ do i = first_line, min (nlines, first_line + ybavg - 1) {
+ # Get line from input image.
+ a = imgs2r (im, xoff, xoff + npix - 1, i, i)
+
+ # Block average line in X.
+ if (xbavg > 1) {
+ # First block average only the full blocks.
+ nfull_blks = npix / xbavg
+ call abavr (Memr[a], Memr[a], nfull_blks, xbavg)
+
+ # Now average the final partial block, if any.
+ if (nfull_blks < nblks_x) {
+ sum = 0.0
+ count = 0
+ do j = nfull_blks * xbavg + 1, npix {
+ sum = sum + Memr[a+j-1]
+ count = count + 1
+ }
+ Memr[a+nblks_x-1] = sum / count
+ }
+ }
+
+ # Add line into block sum. Keep track of number of lines in sum
+ # so that we can compute block average later.
+ if (ybavg > 1) {
+ call aaddr (Memr[a], Memr[b], Memr[b], nblks_x)
+ nlines_in_sum = nlines_in_sum + 1
+ }
+ }
+
+ # Compute the block average in Y from the sum of all lines block
+ # averaged in X. Overwrite buffer A, the buffer returned by IMIO.
+ # This is kosher because the block averaged line is never longer
+ # than an input line.
+
+ if (ybavg > 1)
+ call adivkr (Memr[b], real(nlines_in_sum), Memr[a], nblks_x)
+
+ call sfree (sp)
+ return (a)
+end
diff --git a/pkg/images/tv/iis/src/snap.x b/pkg/images/tv/iis/src/snap.x
new file mode 100644
index 00000000..12694568
--- /dev/null
+++ b/pkg/images/tv/iis/src/snap.x
@@ -0,0 +1,64 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <imhdr.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# SNAP -- Take a picture!!
+
+procedure snap()
+
+char token[SZ_LINE]
+int tok
+char fname[SZ_FNAME]
+int snap_color
+
+include "cv.com"
+
+begin
+ snap_color = IDS_SNAP_MONO # default color for snap
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] != 'c') {
+ call eprintf ("unknown snap argument: %s\n")
+ call pargstr (token)
+ return
+ } else {
+ # snap colors: r, g, b, rgb, m (monochrome) == bw (black/white)
+ switch (token[2]) {
+ case 'm':
+ snap_color = IDS_SNAP_MONO
+
+ case 'r':
+ if ((token[3] == 'g') && (token[4] == 'b') )
+ snap_color = IDS_SNAP_RGB
+ else
+ snap_color = IDS_SNAP_RED
+
+ case 'g':
+ snap_color = IDS_SNAP_GREEN
+
+ case 'b':
+ if (token[3] == 'w')
+ snap_color = IDS_SNAP_MONO
+ else
+ snap_color = IDS_SNAP_BLUE
+
+ default:
+ call eprintf ("Unknown snap color: %c\n")
+ call pargc (token[2])
+ return
+ }
+ }
+ } else if (tok != TOK_NEWLINE) {
+ call eprintf ("unexpected argument to snap: %s\n")
+ call pargstr (token)
+ return
+ }
+
+ call clgstr("snap_file", fname, SZ_FNAME)
+ call cvsnap (fname, snap_color)
+end
diff --git a/pkg/images/tv/iis/src/split.x b/pkg/images/tv/iis/src/split.x
new file mode 100644
index 00000000..393fc218
--- /dev/null
+++ b/pkg/images/tv/iis/src/split.x
@@ -0,0 +1,95 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# SPLIT -- set the split screen point
+
+procedure split()
+
+char token[SZ_LINE]
+int tok
+int nchar, ctoi()
+int i, x, y
+real xr, yr
+int ctor()
+bool a_real
+
+define errmsg 10
+
+include "cv.com"
+
+begin
+ a_real = false
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ switch(token[1]) {
+ case 'c':
+ x = cv_xcen
+ y = cv_ycen
+
+ case 'o':
+ x = 1
+ y = 1
+
+ case 'n', 'p': # n: ndc, p: pixel
+ if (token[1] == 'n')
+ a_real = true
+ if (IS_DIGIT(token[2]))
+ i = 2
+ else {
+ call gargtok (tok, token, SZ_LINE)
+ if (tok != TOK_NUMBER) {
+errmsg
+ call eprintf ("bad split pixel: %s\n")
+ call pargstr (token)
+ return
+ } else
+ i = 1
+ }
+ if (a_real)
+ nchar = ctor (token, i, xr)
+ else
+ nchar = ctoi (token, i, x)
+ if (nchar == 0) {
+ call eprintf ("No conversion, ")
+ goto errmsg
+ }
+ call gargtok (tok, token, SZ_LINE)
+ if (tok == TOK_PUNCTUATION)
+ call gargtok (tok, token, SZ_LINE)
+ i = 1
+ if (a_real)
+ nchar = ctor (token, i, yr)
+ else
+ nchar = ctoi (token, i, y)
+ if (nchar == 0) {
+ call eprintf ("No conversion, ")
+ goto errmsg
+ }
+
+ default:
+ call eprintf ("unknown split code: %c\n")
+ call pargc (token[1])
+ return
+ }
+ }
+ # Convert to NDC, BUT note, that as x and y range from 1 through
+ # cv_[xy]res, xr and yr will never be 1.0---and they must not be
+ # (see cvsplit())
+ if (!a_real ) {
+ xr = real(x-1) / cv_xres
+ yr = real(y-1) / cv_xres
+ }
+ if ( xr < 0 )
+ xr = 0
+ if ( yr < 0 )
+ yr = 0
+ if ( xr >= 1.0 )
+ xr = real(cv_xres-1)/cv_xres
+ if ( yr >= 1.0 )
+ yr = real(cv_yres-1)/cv_yres
+ call cvsplit (xr, yr)
+end
diff --git a/pkg/images/tv/iis/src/tell.x b/pkg/images/tv/iis/src/tell.x
new file mode 100644
index 00000000..cce4987e
--- /dev/null
+++ b/pkg/images/tv/iis/src/tell.x
@@ -0,0 +1,24 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+
+include "../lib/ids.h"
+
+# TELL -- Tell user about display state
+
+procedure tell()
+
+short f[IDS_MAXIMPL+2] # Ultimately, want an array terminated
+ # with IDS_EOD as usual
+
+include "cv.com"
+
+begin
+ # We don't know much, do we?
+
+ call cvwhich(f)
+ if ( f[1] > 0) {
+ call eprintf ("Frame %d, at least, is on.\n")
+ call pargs (f[1])
+ } else
+ call eprintf ("No frames are on.\n")
+end
diff --git a/pkg/images/tv/iis/src/text.x b/pkg/images/tv/iis/src/text.x
new file mode 100644
index 00000000..32623786
--- /dev/null
+++ b/pkg/images/tv/iis/src/text.x
@@ -0,0 +1,71 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include "../lib/ids.h"
+
+# TEXT -- put text into image planes or graphics bit planes
+
+procedure text()
+
+char token[SZ_LINE]
+int tok, ip, cnum
+short frames[IDS_MAXIMPL+2] # frames, graphics, EOD
+short colors[IDS_MAXGCOLOR]
+real x, y
+int button, cv_wtbut()
+char line[SZ_LINE]
+real size, clgetr()
+
+begin
+ frames[1] = ERR
+ colors[1] = ERR
+
+ # which frames for text
+
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'f') {
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (token[1] == 'c') {
+ call cv_color (token[2], colors)
+ if (colors[1] == ERR)
+ return
+ }
+ } else if (tok == TOK_NUMBER) {
+ call cv_frame (token[1], frames)
+ if (frames[1] == ERR)
+ return
+ }
+ if ( (frames[1] == ERR) && (colors[1] == ERR)) {
+ call eprintf ("Inadequate text specification: %s\n")
+ call pargstr (token)
+ return
+ }
+
+ call gargstr (line, SZ_LINE)
+
+ # Prompt user to set cursor
+
+ call eprintf ("Set cursor to desired location, then press any button\n")
+ button = cv_wtbut()
+
+ # Set up kernel for write
+ if (frames[1] != ERR) {
+ cnum = frames[1]
+ call cv_iset (frames)
+ } else {
+ cnum = 16 # SORRY, is IIS specific - we should do better
+ call cv_gset (colors)
+ }
+ call cv_rcur (cnum, x, y)
+
+ size = clgetr("textsize")
+ ip = 1
+ while (IS_WHITE(line[ip]))
+ ip = ip + 1
+ call cvtext (x, y, line[ip], size)
+end
diff --git a/pkg/images/tv/iis/src/window.x b/pkg/images/tv/iis/src/window.x
new file mode 100644
index 00000000..e3523a90
--- /dev/null
+++ b/pkg/images/tv/iis/src/window.x
@@ -0,0 +1,181 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# WINDOW -- window the display.
+
+procedure window()
+
+char token[SZ_LINE]
+int tok, cnum
+short frames[IDS_MAXIMPL+2] # frames, graphics, EOD
+short colors[IDS_MAXGCOLOR]
+real x, y
+real xold, yold
+int device, button, cv_rdbut()
+short wdata[16]
+int n, first, last
+real istart, iend, slope
+
+include "cv.com"
+
+begin
+ # Find out if want to change output tables
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (( tok == TOK_IDENTIFIER) && (token[1] == 'o')) {
+ device = IDS_OUTPUT_LUT
+ slope = 4.0 # Device dependent !!
+ } else {
+ device = IDS_FRAME_LUT
+ slope = 1.0
+ # reset input pointers; same as having pushed back token
+ call reset_scan
+ call gargtok (tok, token, SZ_LINE)
+ }
+
+ # Default to all frames, all colors
+ frames[1] = IDS_EOD
+ colors[1] = IDS_EOD
+
+ # which frames to window
+
+ repeat {
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (tok == TOK_IDENTIFIER) {
+ if (token[1] == 'f') {
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (token[1] == 'c') {
+ call cv_color (token[2], colors)
+ if (colors[1] == ERR)
+ return
+ } else {
+ call eprintf ("Unknown window argument: %s\n")
+ call pargstr (token)
+ return
+ }
+ } else if (tok == TOK_NUMBER) {
+ call cv_frame (token[1], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (tok != TOK_NEWLINE) {
+ call eprintf ("Unexpected window input: %s\n")
+ call pargstr (token)
+ return
+ }
+ } until ( tok == TOK_NEWLINE)
+
+ # rememeber current cursor postion
+
+ cnum = 0
+ call cv_rcur (cnum, xold, yold)
+
+ # Now set up loop to window display; we need to read back
+ # display but cannot, so for now, use "common" variables
+ # If first time, use defaults.
+
+ if (cv_xwinc == -1) {
+ if (slope == 1.0) {
+ cv_xwinc = 0.25
+ cv_ywinc = .75
+ } else {
+ cv_xwinc = .0625
+ cv_ywinc = .9375
+ }
+ }
+ call cv_scraw (cv_xwinc, cv_ywinc)
+
+ button = cv_rdbut() # clear buttons by reading them
+ call eprintf ("Press any button when done\n")
+
+ # The mapping equation is table value = 0.25 + y * (i-x)
+ # where i runs from 0 to 1.0, x ranges from 0. to 1.0 and y
+ # from 0 to large.
+
+ repeat {
+ call cv_rcraw (cv_xwinc, cv_ywinc)
+ x = cv_xwinc
+ y = (cv_ywinc - 0.5) * 4
+ # Keep y from equalling 2 or -2 :
+ if (y >= 2.)
+ y = 1.99
+ else if ( y <= -2.0)
+ y = -1.99
+ if (y > 1.)
+ y = 1. / (2. - y)
+ else if (y < -1.)
+ y = -1. / (2. + y)
+
+ if ( y == 0.0) {
+ iend = 1.0
+ istart = 0.0
+ first = 0
+ last = GKI_MAXNDC
+ } else if ( y > 0.) {
+ istart = x - 0.25/y
+ iend = 1.0/y + istart
+ first = 0
+ last = GKI_MAXNDC
+ } else {
+ iend = x - 0.25/y
+ istart = 1.0/y + iend
+ first = GKI_MAXNDC
+ last = 0
+ }
+ if (istart < 0.)
+ istart = 0.
+ if (iend > 1.0)
+ iend = 1.0
+ if (istart > 1.0)
+ istart = 1.0
+ if (iend < istart)
+ iend = istart
+ wdata[1] = 0
+ if ( istart > 0.) {
+ wdata[2] = first
+ wdata[3] = istart * GKI_MAXNDC
+ wdata[4] = first
+ n = 5
+ } else {
+ wdata[2] = (0.25 -x*y) * GKI_MAXNDC
+ n = 3
+ }
+ wdata[n] = iend * GKI_MAXNDC
+ if ( iend < 1.0) {
+ # In this case, we reach max/min y value before end of table, so
+ # extend it horizontally to end
+ wdata[n+1] = last
+ wdata[n+2] = GKI_MAXNDC
+ wdata[n+3] = last
+ n = n + 3
+ } else {
+ wdata[n+1] = (0.25 + y * (1.0 - x)) * GKI_MAXNDC
+ n = n + 1
+ }
+ call cvwlut (device, frames, colors, wdata, n)
+ button = cv_rdbut()
+ } until (button > 0)
+
+ # Restore old cursor position
+ call cv_rcur (cnum, xold, yold)
+
+ # Tell the user what final mapping was
+ call printf ("window: from (%5.3f,%5.3f) to (%5.3f,%5.3f)\n")
+ call pargr (istart)
+ if (istart > 0.)
+ call pargr (real(first)/GKI_MAXNDC)
+ else
+ call pargr (real(wdata[2])/GKI_MAXNDC)
+ call pargr (iend)
+ if (iend < 1.0)
+ call pargr (real(last)/GKI_MAXNDC)
+ else
+ call pargr (real(wdata[n])/GKI_MAXNDC)
+
+end
diff --git a/pkg/images/tv/iis/src/zoom.x b/pkg/images/tv/iis/src/zoom.x
new file mode 100644
index 00000000..c7e7bff7
--- /dev/null
+++ b/pkg/images/tv/iis/src/zoom.x
@@ -0,0 +1,60 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctotok.h>
+include <ctype.h>
+include <gki.h>
+include "../lib/ids.h"
+
+# ZOOM -- zoom, then pan, the display. If zoom power == 1, then
+# don't bother panning.
+
+procedure zoom()
+
+char token[SZ_LINE]
+int tok, count, power, cnum
+short frames[IDS_MAXIMPL+2] # frames, graphics, EOD
+real x, y
+int ctoi, ip
+
+include "cv.com"
+
+begin
+ # get power for zoom
+
+ call gargtok (tok, token, SZ_LINE)
+ if (tok != TOK_NUMBER) {
+ call eprintf ("Bad zoom power: %s\n")
+ call pargstr (token)
+ return
+ }
+ ip = 1
+ count = ctoi(token, ip, power)
+
+ # which frames to zoom
+
+ frames[1] = IDS_EOD # default all frames
+ call gargtok (tok, token, SZ_LINE)
+ call strlwr (token)
+ if (token[1] == 'f') {
+ call cv_frame (token[2], frames)
+ if (frames[1] == ERR)
+ return
+ } else if (tok == TOK_NUMBER) {
+ call cv_frame (token[1], frames)
+ if (frames[1] == ERR)
+ return
+ } else {
+ call eprintf ("Unexpected input: %s\n")
+ call pargstr (token)
+ return
+ }
+
+ # where to zoom ... find which frame to read cursor position from
+
+ cnum = frames[1]
+ if (cnum == IDS_EOD)
+ cnum = 0
+ call cv_rcur (cnum, x, y)
+ call cvzoom (frames, power, x, y)
+ call pansub (frames)
+end
diff --git a/pkg/images/tv/iis/src/zscale.x b/pkg/images/tv/iis/src/zscale.x
new file mode 100644
index 00000000..bfb0b116
--- /dev/null
+++ b/pkg/images/tv/iis/src/zscale.x
@@ -0,0 +1,457 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+
+.help zscale
+.nf ___________________________________________________________________________
+ZSCALE -- Compute the optimal Z1, Z2 (range of greyscale values to be
+displayed) of an image. For efficiency a statistical subsample of an image
+is used. The pixel sample evenly subsamples the image in x and y. The entire
+image is used if the number of pixels in the image is smaller than the desired
+sample.
+
+The sample is accumulated in a buffer and sorted by greyscale value.
+The median value is the central value of the sorted array. The slope of a
+straight line fitted to the sorted sample is a measure of the standard
+deviation of the sample about the median value. Our algorithm is to sort
+the sample and perform an iterative fit of a straight line to the sample,
+using pixel rejection to omit gross deviants near the endpoints. The fitted
+straight line is the transfer function used to map image Z into display Z.
+If more than half the pixels are rejected the full range is used. The slope
+of the fitted line is divided by the user-supplied contrast factor and the
+final Z1 and Z2 are computed, taking the origin of the fitted line at the
+median value.
+.endhelp ______________________________________________________________________
+
+define MIN_NPIXELS 5 # smallest permissible sample
+define MAX_REJECT 0.5 # max frac. of pixels to be rejected
+define GOOD_PIXEL 0 # use pixel in fit
+define BAD_PIXEL 1 # ignore pixel in all computations
+define REJECT_PIXEL 2 # reject pixel after a bit
+define KREJ 2.5 # k-sigma pixel rejection factor
+define MAX_ITERATIONS 5 # maximum number of fitline iterations
+
+
+# ZSCALE -- Sample the image and compute Z1 and Z2.
+
+procedure zscale (im, z1, z2, contrast, optimal_sample_size, len_stdline)
+
+pointer im # image to be sampled
+real z1, z2 # output min and max greyscale values
+real contrast # adj. to slope of transfer function
+int optimal_sample_size # desired number of pixels in sample
+int len_stdline # optimal number of pixels per line
+
+int npix, minpix, ngoodpix, center_pixel, ngrow
+real zmin, zmax, median
+real zstart, zslope
+pointer sample, left
+int zsc_sample_image(), zsc_fit_line()
+
+begin
+ # Subsample the image.
+ npix = zsc_sample_image (im, sample, optimal_sample_size, len_stdline)
+ center_pixel = max (1, (npix + 1) / 2)
+
+ # Sort the sample, compute the minimum, maximum, and median pixel
+ # values.
+
+ call asrtr (Memr[sample], Memr[sample], npix)
+ zmin = Memr[sample]
+ zmax = Memr[sample+npix-1]
+
+ # The median value is the average of the two central values if there
+ # are an even number of pixels in the sample.
+
+ left = sample + center_pixel - 1
+ if (mod (npix, 2) == 1 || center_pixel >= npix)
+ median = Memr[left]
+ else
+ median = (Memr[left] + Memr[left+1]) / 2
+
+ # Fit a line to the sorted sample vector. If more than half of the
+ # pixels in the sample are rejected give up and return the full range.
+ # If the user-supplied contrast factor is not 1.0 adjust the scale
+ # accordingly and compute Z1 and Z2, the y intercepts at indices 1 and
+ # npix.
+
+ minpix = max (MIN_NPIXELS, int (npix * MAX_REJECT))
+ ngrow = max (1, nint (npix * .01))
+ ngoodpix = zsc_fit_line (Memr[sample], npix, zstart, zslope,
+ KREJ, ngrow, MAX_ITERATIONS)
+
+ if (ngoodpix < minpix) {
+ z1 = zmin
+ z2 = zmax
+ } else {
+ if (contrast > 0)
+ zslope = zslope / contrast
+ z1 = max (zmin, median - (center_pixel - 1) * zslope)
+ z2 = min (zmax, median + (npix - center_pixel) * zslope)
+ }
+
+ call mfree (sample, TY_REAL)
+end
+
+
+# ZSC_SAMPLE_IMAGE -- Extract an evenly gridded subsample of the pixels from
+# a two-dimensional image into a one-dimensional vector.
+
+int procedure zsc_sample_image (im, sample, optimal_sample_size, len_stdline)
+
+pointer im # image to be sampled
+pointer sample # output vector containing the sample
+int optimal_sample_size # desired number of pixels in sample
+int len_stdline # optimal number of pixels per line
+
+int ncols, nlines, col_step, line_step, maxpix, line
+int opt_npix_per_line, npix_per_line
+int opt_nlines_in_sample, min_nlines_in_sample, max_nlines_in_sample
+pointer op
+pointer imgl2r()
+
+begin
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+
+ # Compute the number of pixels each line will contribute to the sample,
+ # and the subsampling step size for a line. The sampling grid must
+ # span the whole line on a uniform grid.
+
+ opt_npix_per_line = min (ncols, len_stdline)
+ col_step = (ncols + opt_npix_per_line-1) / opt_npix_per_line
+ npix_per_line = (ncols + col_step-1) / col_step
+
+ # Compute the number of lines to sample and the spacing between lines.
+ # We must ensure that the image is adequately sampled despite its
+ # size, hence there is a lower limit on the number of lines in the
+ # sample. We also want to minimize the number of lines accessed when
+ # accessing a large image, because each disk seek and read is expensive.
+ # The number of lines extracted will be roughly the sample size divided
+ # by len_stdline, possibly more if the lines are very short.
+
+ min_nlines_in_sample = max (1, optimal_sample_size / len_stdline)
+ opt_nlines_in_sample = max(min_nlines_in_sample, min(nlines,
+ (optimal_sample_size + npix_per_line-1) / npix_per_line))
+ line_step = max (1, nlines / (opt_nlines_in_sample))
+ max_nlines_in_sample = (nlines + line_step-1) / line_step
+
+ # Allocate space for the output vector. Buffer must be freed by our
+ # caller.
+
+ maxpix = npix_per_line * max_nlines_in_sample
+ call malloc (sample, maxpix, TY_REAL)
+
+# call eprintf ("sample: x[%d:%d:%d] y[%d:%d:%d]\n")
+# call pargi(1);call pargi(ncols); call pargi(col_step)
+# call pargi((line_step+1)/2); call pargi(nlines); call pargi(line_step)
+
+ # Extract the vector.
+ op = sample
+ do line = (line_step + 1) / 2, nlines, line_step {
+ call zsc_subsample (Memr[imgl2r(im,line)], Memr[op],
+ npix_per_line, col_step)
+ op = op + npix_per_line
+ if (op - sample + npix_per_line > maxpix)
+ break
+ }
+
+ return (op - sample)
+end
+
+
+# ZSC_SUBSAMPLE -- Subsample an image line. Extract the first pixel and
+# every "step"th pixel thereafter for a total of npix pixels.
+
+procedure zsc_subsample (a, b, npix, step)
+
+real a[ARB]
+real b[npix]
+int npix, step
+int ip, i
+
+begin
+ if (step <= 1)
+ call amovr (a, b, npix)
+ else {
+ ip = 1
+ do i = 1, npix {
+ b[i] = a[ip]
+ ip = ip + step
+ }
+ }
+end
+
+
+# ZSC_FIT_LINE -- Fit a straight line to a data array of type real. This is
+# an iterative fitting algorithm, wherein points further than ksigma from the
+# current fit are excluded from the next fit. Convergence occurs when the
+# next iteration does not decrease the number of pixels in the fit, or when
+# there are no pixels left. The number of pixels left after pixel rejection
+# is returned as the function value.
+
+int procedure zsc_fit_line (data, npix, zstart, zslope, krej, ngrow, maxiter)
+
+real data[npix] # data to be fitted
+int npix # number of pixels before rejection
+real zstart # Z-value of pixel data[1] (output)
+real zslope # dz/pixel (output)
+real krej # k-sigma pixel rejection factor
+int ngrow # number of pixels of growing
+int maxiter # max iterations
+
+int i, ngoodpix, last_ngoodpix, minpix, niter
+real xscale, z0, dz, x, z, mean, sigma, threshold
+double sumxsqr, sumxz, sumz, sumx, rowrat
+pointer sp, flat, badpix, normx
+int zsc_reject_pixels(), zsc_compute_sigma()
+
+begin
+ call smark (sp)
+
+ if (npix <= 0)
+ return (0)
+ else if (npix == 1) {
+ zstart = data[1]
+ zslope = 0.0
+ return (1)
+ } else
+ xscale = 2.0 / (npix - 1)
+
+ # Allocate a buffer for data minus fitted curve, another for the
+ # normalized X values, and another to flag rejected pixels.
+
+ call salloc (flat, npix, TY_REAL)
+ call salloc (normx, npix, TY_REAL)
+ call salloc (badpix, npix, TY_SHORT)
+ call aclrs (Mems[badpix], npix)
+
+ # Compute normalized X vector. The data X values [1:npix] are
+ # normalized to the range [-1:1]. This diagonalizes the lsq matrix
+ # and reduces its condition number.
+
+ do i = 0, npix - 1
+ Memr[normx+i] = i * xscale - 1.0
+
+ # Fit a line with no pixel rejection. Accumulate the elements of the
+ # matrix and data vector. The matrix M is diagonal with
+ # M[1,1] = sum x**2 and M[2,2] = ngoodpix. The data vector is
+ # DV[1] = sum (data[i] * x[i]) and DV[2] = sum (data[i]).
+
+ sumxsqr = 0
+ sumxz = 0
+ sumx = 0
+ sumz = 0
+
+ do i = 1, npix {
+ x = Memr[normx+i-1]
+ z = data[i]
+ sumxsqr = sumxsqr + (x ** 2)
+ sumxz = sumxz + z * x
+ sumz = sumz + z
+ }
+# call eprintf ("\t%10g %10g %10g\n")
+# call pargd(sumxsqr); call pargd(sumxz); call pargd(sumz)
+
+ # Solve for the coefficients of the fitted line.
+ z0 = sumz / npix
+ dz = sumxz / sumxsqr
+
+# call eprintf ("fit: z0=%g, dz=%g\n")
+# call pargr(z0); call pargr(dz)
+
+ # Iterate, fitting a new line in each iteration. Compute the flattened
+ # data vector and the sigma of the flat vector. Compute the lower and
+ # upper k-sigma pixel rejection thresholds. Run down the flat array
+ # and detect pixels to be rejected from the fit. Reject pixels from
+ # the fit by subtracting their contributions from the matrix sums and
+ # marking the pixel as rejected.
+
+ ngoodpix = npix
+ minpix = max (MIN_NPIXELS, int (npix * MAX_REJECT))
+
+ for (niter=1; niter <= maxiter; niter=niter+1) {
+ last_ngoodpix = ngoodpix
+
+ # Subtract the fitted line from the data array.
+ call zsc_flatten_data (data, Memr[flat], Memr[normx], npix, z0, dz)
+
+ # Compute the k-sigma rejection threshold. In principle this
+ # could be more efficiently computed using the matrix sums
+ # accumulated when the line was fitted, but there are problems with
+ # numerical stability with that approach.
+
+ ngoodpix = zsc_compute_sigma (Memr[flat], Mems[badpix], npix,
+ mean, sigma)
+ threshold = sigma * krej
+
+ # Detect and reject pixels further than ksigma from the fitted
+ # line.
+ ngoodpix = zsc_reject_pixels (data, Memr[flat], Memr[normx],
+ Mems[badpix], npix, sumxsqr, sumxz, sumx, sumz, threshold,
+ ngrow)
+
+ # Solve for the coefficients of the fitted line. Note that after
+ # pixel rejection the sum of the X values need no longer be zero.
+
+ if (ngoodpix > 0) {
+ rowrat = sumx / sumxsqr
+ z0 = (sumz - rowrat * sumxz) / (ngoodpix - rowrat * sumx)
+ dz = (sumxz - z0 * sumx) / sumxsqr
+ }
+
+# call eprintf ("fit: z0=%g, dz=%g, threshold=%g, npix=%d\n")
+# call pargr(z0); call pargr(dz); call pargr(threshold); call pargi(ngoodpix)
+
+ if (ngoodpix >= last_ngoodpix || ngoodpix < minpix)
+ break
+ }
+
+ # Transform the line coefficients back to the X range [1:npix].
+ zstart = z0 - dz
+ zslope = dz * xscale
+
+ call sfree (sp)
+ return (ngoodpix)
+end
+
+
+# ZSC_FLATTEN_DATA -- Compute and subtract the fitted line from the data array,
+# returned the flattened data in FLAT.
+
+procedure zsc_flatten_data (data, flat, x, npix, z0, dz)
+
+real data[npix] # raw data array
+real flat[npix] # flattened data (output)
+real x[npix] # x value of each pixel
+int npix # number of pixels
+real z0, dz # z-intercept, dz/dx of fitted line
+int i
+
+begin
+ do i = 1, npix
+ flat[i] = data[i] - (x[i] * dz + z0)
+end
+
+
+# ZSC_COMPUTE_SIGMA -- Compute the root mean square deviation from the
+# mean of a flattened array. Ignore rejected pixels.
+
+int procedure zsc_compute_sigma (a, badpix, npix, mean, sigma)
+
+real a[npix] # flattened data array
+short badpix[npix] # bad pixel flags (!= 0 if bad pixel)
+int npix
+real mean, sigma # (output)
+
+real pixval
+int i, ngoodpix
+double sum, sumsq, temp
+
+begin
+ sum = 0
+ sumsq = 0
+ ngoodpix = 0
+
+ # Accumulate sum and sum of squares.
+ do i = 1, npix
+ if (badpix[i] == GOOD_PIXEL) {
+ pixval = a[i]
+ ngoodpix = ngoodpix + 1
+ sum = sum + pixval
+ sumsq = sumsq + pixval ** 2
+ }
+
+ # Compute mean and sigma.
+ switch (ngoodpix) {
+ case 0:
+ mean = INDEF
+ sigma = INDEF
+ case 1:
+ mean = sum
+ sigma = INDEF
+ default:
+ mean = sum / ngoodpix
+ temp = sumsq / (ngoodpix - 1) - sum**2 / (ngoodpix * (ngoodpix - 1))
+ if (temp < 0) # possible with roundoff error
+ sigma = 0.0
+ else
+ sigma = sqrt (temp)
+ }
+
+ return (ngoodpix)
+end
+
+
+# ZSC_REJECT_PIXELS -- Detect and reject pixels more than "threshold" greyscale
+# units from the fitted line. The residuals about the fitted line are given
+# by the "flat" array, while the raw data is in "data". Each time a pixel
+# is rejected subtract its contributions from the matrix sums and flag the
+# pixel as rejected. When a pixel is rejected reject its neighbors out to
+# a specified radius as well. This speeds up convergence considerably and
+# produces a more stringent rejection criteria which takes advantage of the
+# fact that bad pixels tend to be clumped. The number of pixels left in the
+# fit is returned as the function value.
+
+int procedure zsc_reject_pixels (data, flat, normx, badpix, npix,
+ sumxsqr, sumxz, sumx, sumz, threshold, ngrow)
+
+real data[npix] # raw data array
+real flat[npix] # flattened data array
+real normx[npix] # normalized x values of pixels
+short badpix[npix] # bad pixel flags (!= 0 if bad pixel)
+int npix
+double sumxsqr,sumxz,sumx,sumz # matrix sums
+real threshold # threshold for pixel rejection
+int ngrow # number of pixels of growing
+
+int ngoodpix, i, j
+real residual, lcut, hcut
+double x, z
+
+begin
+ ngoodpix = npix
+ lcut = -threshold
+ hcut = threshold
+
+ do i = 1, npix
+ if (badpix[i] == BAD_PIXEL)
+ ngoodpix = ngoodpix - 1
+ else {
+ residual = flat[i]
+ if (residual < lcut || residual > hcut) {
+ # Reject the pixel and its neighbors out to the growing
+ # radius. We must be careful how we do this to avoid
+ # directional effects. Do not turn off thresholding on
+ # pixels in the forward direction; mark them for rejection
+ # but do not reject until they have been thresholded.
+ # If this is not done growing will not be symmetric.
+
+ do j = max(1,i-ngrow), min(npix,i+ngrow) {
+#call eprintf ("\t\t%d->%d\tcheck\n");call pargi(j); call pargs(badpix[j])
+ if (badpix[j] != BAD_PIXEL) {
+ if (j <= i) {
+ x = normx[j]
+ z = data[j]
+#call eprintf ("\treject [%d:%6g]=%6g sum[xsqr,xz,z]\n")
+#call pargi(j); call pargd(x); call pargd(z)
+#call eprintf ("\t%10g %10g %10g\n")
+#call pargd(sumxsqr); call pargd(sumxz); call pargd(sumz)
+ sumxsqr = sumxsqr - (x ** 2)
+ sumxz = sumxz - z * x
+ sumx = sumx - x
+ sumz = sumz - z
+#call eprintf ("\t%10g %10g %10g\n")
+#call pargd(sumxsqr); call pargd(sumxz); call pargd(sumz)
+ badpix[j] = BAD_PIXEL
+ ngoodpix = ngoodpix - 1
+ } else
+ badpix[j] = REJECT_PIXEL
+#call eprintf ("\t\t%d->%d\tset\n");call pargi(j); call pargs(badpix[j])
+ }
+ }
+ }
+ }
+
+ return (ngoodpix)
+end