aboutsummaryrefslogtreecommitdiff
path: root/pkg/images/tv/display/t_display.x
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/images/tv/display/t_display.x')
-rw-r--r--pkg/images/tv/display/t_display.x885
1 files changed, 885 insertions, 0 deletions
diff --git a/pkg/images/tv/display/t_display.x b/pkg/images/tv/display/t_display.x
new file mode 100644
index 00000000..f4156f39
--- /dev/null
+++ b/pkg/images/tv/display/t_display.x
@@ -0,0 +1,885 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <imset.h>
+include <imhdr.h>
+include <error.h>
+include <pmset.h>
+include "display.h"
+include "gwindow.h"
+include "iis.h"
+
+# DISPLAY - Display 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
+# to FIO as a file and is accessed herein via IMIO as just another imagefile.
+# The physical characteristics of the display (i.e., X, Y, and Z resolution)
+# are taken from the image header. The display frame buffer is the pixel
+# storage "file".
+
+procedure t_display()
+
+char image[SZ_FNAME] # Image to display
+int frame # Display frame
+int erase # Erase frame?
+
+int i
+pointer sp, wdes, im, ds
+
+bool clgetb()
+int clgeti(), btoi(), imd_wcsver(), imtlen(), imtgetim()
+pointer immap(), imd_mapframe1(), imtopenp()
+errchk immap, imd_mapframe1
+errchk ds_getparams, ds_setwcs, ds_load_display, ds_erase_border
+
+begin
+ call smark (sp)
+ call salloc (wdes, LEN_WDES, TY_STRUCT)
+ call aclri (Memi[wdes], LEN_WDES)
+
+ # Open input imagefile.
+ im = imtopenp ("image")
+ if (imtlen (im) != 1)
+ call error (1, "Only one image may be displayed")
+ i = imtgetim (im, image, SZ_FNAME)
+ call imtclose (im)
+ #call clgstr ("image", image, SZ_FNAME)
+ im = immap (image, READ_ONLY, 0)
+ if (IM_NDIM(im) <= 0)
+ call error (1, "image has no pixels")
+
+ # Query server to get the WCS version, this also tells us whether
+ # we can use the all 16 supported frames.
+ if (imd_wcsver() == 0)
+ call clputi ("display.frame.p_max", 4)
+ else
+ call clputi ("display.frame.p_max", 16)
+
+
+ # Open display device as an image.
+ frame = clgeti ("frame")
+ W_FRAME(wdes) = frame
+
+ erase = btoi (clgetb ("erase"))
+ if (erase == YES)
+ ds = imd_mapframe1 (frame, WRITE_ONLY,
+ btoi (clgetb ("select_frame")), erase)
+ else
+ ds = imd_mapframe1 (frame, READ_WRITE,
+ btoi (clgetb ("select_frame")), erase)
+
+ # Get display parameters and set up transformation.
+ call ds_getparams (im, ds, wdes)
+
+ # Compute and output the screen to image pixel WCS.
+ call ds_setwcs (im, ds, wdes, image, frame)
+
+ # Display the image and zero the border if necessary.
+ call ds_load_display (im, ds, wdes)
+ if (!clgetb ("erase") && clgetb ("border_erase"))
+ call ds_erase_border (im, ds, wdes)
+
+ # Free storage.
+ call maskcolor_free (W_OCOLORS(wdes))
+ call maskcolor_free (W_BPCOLORS(wdes))
+ do i = 0, W_MAXWC
+ if (W_UPTR(W_WC(wdes,i)) != NULL)
+ call ds_ulutfree (W_UPTR(W_WC(wdes,i)))
+ call imunmap (ds)
+ call imunmap (im)
+
+ 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. If "repeat" mode is enabled, read the graphics descriptor
+# file and reuse the transformations therein.
+
+procedure ds_getparams (im, ds, wdes)
+
+pointer im, ds, wdes #I Image, display, and graphics descriptors
+
+bool fill, zscale_flag, zrange_flag, zmap_flag
+real xcenter, ycenter, xsize, ysize
+real xmag, ymag, xscale, yscale, pxsize, pysize
+real z1, z2, contrast
+int nsample, ncols, nlines
+pointer wnwin, wdwin, wwwin, wipix, wdpix, zpm, bpm
+pointer sp, str, ztrans, lutfile
+
+int clgeti(), clgwrd(), nowhite()
+real clgetr()
+pointer maskcolor_map(), ds_pmmap(), zsc_pmsection()
+pointer ds_ulutalloc()
+bool streq(), clgetb()
+errchk maskcolor_map, ds_pmmap, zsc_pmsection, mzscale
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (ztrans, SZ_FNAME, TY_CHAR)
+
+ # Get overlay mask and colors.
+ call clgstr ("overlay", W_OVRLY(wdes), W_SZSTRING)
+ call clgstr ("ocolors", Memc[str], SZ_LINE)
+ W_OCOLORS(wdes) = maskcolor_map (Memc[str])
+
+ # Get bad pixel mask.
+ call clgstr ("bpmask", W_BPM(wdes), W_SZSTRING)
+ W_BPDISP(wdes) = clgwrd ("bpdisplay", Memc[str], SZ_LINE, BPDISPLAY)
+ call clgstr ("bpcolors", Memc[str], SZ_LINE)
+ W_BPCOLORS(wdes) = maskcolor_map (Memc[str])
+
+ # 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")))
+
+ # Set up a new graphics descriptor structure defining the coordinate
+ # transformation used to map the image into the display frame.
+
+ wnwin = W_WC(wdes,W_NWIN)
+ wdwin = W_WC(wdes,W_DWIN)
+ wwwin = W_WC(wdes,W_WWIN)
+ wipix = W_WC(wdes,W_IPIX)
+ wdpix = W_WC(wdes,W_DPIX)
+
+ # 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.
+
+ fill = clgetb ("fill")
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ if (fill) {
+ # Compute scale in units of window coords per data pixel required
+ # to scale image to fit window.
+
+ xmag = (IM_LEN(ds,1) * xsize) / ncols
+ ymag = (IM_LEN(ds,2) * ysize) / nlines
+
+ if (xmag > ymag)
+ xmag = ymag
+ else
+ ymag = xmag
+
+ } 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 / (IM_LEN(ds,1) / xmag)
+ yscale = 1.0 / (IM_LEN(ds,2) / ymag)
+
+ # Set device window limits in normalized device coordinates.
+ # World coord system 0 is used for the device window.
+
+ W_XS(wnwin) = xcenter - xsize / 2.0
+ W_XE(wnwin) = xcenter + xsize / 2.0
+ W_YS(wnwin) = ycenter - ysize / 2.0
+ W_YE(wnwin) = ycenter + ysize / 2.0
+
+ # Set pixel coordinates of window.
+ # 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. Note that the 0.5 is because NDC has
+ # the screen corner at 0 while screen pixels have the corner at 0.5.
+
+ pxsize = xsize / xscale
+ pysize = ysize / yscale
+
+ W_XS(wdwin) = (ncols / 2.0) - (pxsize / 2.0) + 0.5
+ W_XE(wdwin) = W_XS(wdwin) + pxsize
+ W_YS(wdwin) = (nlines / 2.0) - (pysize / 2.0) + 0.5
+ W_YE(wdwin) = W_YS(wdwin) + pysize
+
+ # Compute X and Y magnification ratios required to map image into
+ # the device window in device pixel units.
+
+ xmag = (W_XE(wnwin)-W_XS(wnwin))*IM_LEN(ds,1)/(W_XE(wdwin)-W_XS(wdwin))
+ ymag = (W_YE(wnwin)-W_YS(wnwin))*IM_LEN(ds,2)/(W_YE(wdwin)-W_YS(wdwin))
+
+ # Compute the coordinates of the image section to be displayed.
+ # Round down if upper pixel is exactly at one-half.
+
+ W_XS(wipix) = max (1, nint(W_XS(wdwin)))
+ W_XE(wipix) = min (ncols, nint(W_XE(wdwin)-1.01))
+ W_YS(wipix) = max (1, nint(W_YS(wdwin)))
+ W_YE(wipix) = min (nlines, nint(W_YE(wdwin)-1.01))
+
+ # Now compute the image and display pixels to be used.
+ # The image may be truncated to fit in the display window.
+ # These are integer coordinates at the pixel centers.
+
+ pxsize = W_XE(wipix) - W_XS(wipix) + 1
+ pysize = W_YE(wipix) - W_YS(wipix) + 1
+ xcenter = (W_XE(wnwin) + W_XS(wnwin)) / 2.0 * IM_LEN(ds,1) + 0.5
+ ycenter = (W_YE(wnwin) + W_YS(wnwin)) / 2.0 * IM_LEN(ds,2) + 0.5
+
+ #W_XS(wdpix) = max (1, nint (xcenter - (pxsize/2.0*xmag) + 0.5))
+ W_XS(wdpix) = max (1, int (xcenter - (pxsize/2.0*xmag) + 0.5))
+ W_XE(wdpix) = min (IM_LEN(ds,1), nint (W_XS(wdpix)+pxsize*xmag - 1.01))
+ #W_YS(wdpix) = max (1, nint (ycenter - (pysize/2.0*ymag) + 0.5))
+ W_YS(wdpix) = max (1, int (ycenter - (pysize/2.0*ymag) + 0.5))
+ W_YE(wdpix) = min (IM_LEN(ds,2), nint (W_YS(wdpix)+pysize*ymag - 1.01))
+
+ # Now adjust the display window to be consistent with the image and
+ # display pixels to be used.
+
+ W_XS(wdwin) = W_XS(wnwin) * IM_LEN(ds,1) + 0.5
+ W_XE(wdwin) = W_XE(wnwin) * IM_LEN(ds,1) + 0.5
+ W_YS(wdwin) = W_YS(wnwin) * IM_LEN(ds,2) + 0.5
+ W_YE(wdwin) = W_YE(wnwin) * IM_LEN(ds,2) + 0.5
+ W_XS(wdwin) = (W_XS(wipix)-0.5) + (W_XS(wdwin)-(W_XS(wdpix)-0.5))/xmag
+ W_XE(wdwin) = (W_XS(wipix)-0.5) + (W_XE(wdwin)-(W_XS(wdpix)-0.5))/xmag
+ W_YS(wdwin) = (W_YS(wipix)-0.5) + (W_YS(wdwin)-(W_YS(wdpix)-0.5))/ymag
+ W_YE(wdwin) = (W_YS(wipix)-0.5) + (W_YE(wdwin)-(W_YS(wdpix)-0.5))/ymag
+
+ # Order of interpolator used for spatial transformation.
+ W_XT(wdwin) = max(0, min(1, clgeti ("order")))
+ W_YT(wdwin) = W_XT(wdwin)
+
+ # Determine the greyscale transformation.
+ call clgstr ("ztrans", Memc[ztrans], SZ_FNAME)
+ if (streq (Memc[ztrans], "log"))
+ W_ZT(wdwin) = W_LOG
+ else if (streq (Memc[ztrans], "linear"))
+ W_ZT(wdwin) = W_LINEAR
+ else if (streq (Memc[ztrans], "none"))
+ W_ZT(wdwin) = W_UNITARY
+ else if (streq (Memc[ztrans], "user")) {
+ W_ZT(wdwin) = W_USER
+ call salloc (lutfile, SZ_FNAME, TY_CHAR)
+ call clgstr ("lutfile", Memc[lutfile], SZ_FNAME)
+ W_UPTR(wdwin) = ds_ulutalloc (Memc[lutfile], z1, z2)
+ } else {
+ call eprintf ("Bad greylevel transformation '%s'\n")
+ call pargstr (Memc[ztrans])
+ W_ZT(wdwin) = W_LINEAR
+ }
+
+ # The zscale, and zrange parameters determine the algorithms for
+ # determining Z1 and Z2, the range of input z values to be mapped
+ # into the fixed range of display greylevels. If sampling and no
+ # sample mask is given then create one as a subsampled image section.
+ # 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.
+
+ if (W_ZT(wdwin) == W_UNITARY || W_ZT(wdwin) == W_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")
+ }
+
+ if (zscale_flag || (zrange_flag && IM_LIMTIME(im) < IM_MTIME(im))) {
+ call clgstr ("zmask", W_ZPM(wdes), W_SZSTRING)
+ nsample = max (100, clgeti ("nsample"))
+ if (nowhite (W_ZPM(wdes), W_ZPM(wdes), W_SZSTRING) > 0) {
+ if (W_ZPM(wdes) == '[')
+ zpm = zsc_pmsection (W_ZPM(wdes), im)
+ else
+ zpm = ds_pmmap (W_ZPM(wdes), im)
+ } else
+ zpm = NULL
+ iferr (bpm = ds_pmmap (W_BPM(wdes), im)) {
+ call erract (EA_WARN)
+ bpm = NULL
+ }
+ }
+
+ 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")
+ call mzscale (im, zpm, bpm, contrast, nsample, z1, z2)
+ if (zpm != NULL)
+ call imunmap (zpm)
+ if (bpm != NULL)
+ call imunmap (bpm)
+
+ } else if (zrange_flag) {
+ # Use the limits in the header if current otherwise get the
+ # minimum and maximum of the sample mask.
+ if (IM_LIMTIME(im) >= IM_MTIME(im)) {
+ z1 = IM_MIN(im)
+ z2 = IM_MAX(im)
+ } else {
+ call mzscale (im, zpm, bpm, 0., nsample, z1, z2)
+ if (zpm != NULL)
+ call imunmap (zpm)
+ if (bpm != NULL)
+ call imunmap (bpm)
+ }
+
+ } else if (zmap_flag) {
+ z1 = clgetr ("z1")
+ z2 = clgetr ("z2")
+ } else {
+ z1 = IM_MIN(ds)
+ z2 = IM_MAX(ds)
+ }
+
+ W_ZS(wdwin) = z1
+ W_ZE(wdwin) = z2
+
+ call printf ("z1=%g z2=%g\n")
+ call pargr (z1)
+ call pargr (z2)
+ call flush (STDOUT)
+
+ # 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[wdwin], Memi[wwwin], LEN_WC)
+ W_UPTR(wwwin) = NULL # should not copy pointers!!
+ call sfree (sp)
+end
+
+
+# DS_SETWCS -- Compute the rotation matrix needed to convert screen coordinates
+# (zero indexed, y-flipped) to image pixel coordinates, allowing both for the
+# transformation from screen space to the image section being displayed, and
+# from the image section to the physical input image.
+#
+# NOTE -- This code assumes that the display device is zero-indexed and
+# y-flipped; this is usually the case, but should be parameterized in the
+# graphcap. This code also assumes that the full device screen is being used,
+# and that we are not assigning multiple WCS to different regions of the screen.
+
+procedure ds_setwcs (im, ds, wdes, image, frame)
+
+pointer im, ds, wdes # image, display, and coordinate descriptors
+char image[SZ_FNAME] # image section name
+int frame # frame
+
+real a, b, c, d, tx, ty
+int ip, i, j, axis[2]
+real sx, sy
+int dx, dy, snx, sny, dnx, dny
+pointer sp, imname, title, wnwin, wdwin
+pointer src, dest, region, objref
+long lv[IM_MAXDIM], pv1[IM_MAXDIM], pv2[IM_MAXDIM]
+
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (imname, SZ_FNAME, TY_CHAR)
+ call salloc (title, SZ_LINE, TY_CHAR)
+ call salloc (region, SZ_FNAME, TY_CHAR)
+ call salloc (objref, SZ_FNAME, TY_CHAR)
+
+ # Compute the rotation matrix needed to transform screen pixel coords
+ # to image section coords.
+
+ wnwin = W_WC(wdes,W_NWIN)
+ wdwin = W_WC(wdes,W_DWIN)
+
+ # X transformation.
+ a = (W_XE(wdwin)-W_XS(wdwin))/((W_XE(wnwin)-W_XS(wnwin))*IM_LEN(ds,1))
+ c = 0.0 # not rotated, cross term is zero
+ tx = W_XS(wdwin) - a * (W_XS(wnwin) * IM_LEN(ds,1))
+
+ # Y transformation.
+ b = 0.0 # not rotated, cross term is zero
+ d = (W_YE(wdwin)-W_YS(wdwin))/((W_YE(wnwin)-W_YS(wnwin))*IM_LEN(ds,2))
+ ty = W_YS(wdwin) - d * (W_YS(wnwin) * IM_LEN(ds,2))
+
+ # Now allow for the Y-flip (origin at upper left in display window).
+ d = -d
+ ty = W_YE(wdwin) - d * ((1.0 - W_YE(wnwin)) * IM_LEN(ds,2))
+
+ # Now translate the screen corner to the center of the screen pixel.
+ tx = tx + 0.5 * a
+ ty = ty + 0.5 * d
+
+ # Determine the logical to physical mapping by evaluating two points.
+ # and determining the axis reduction if any. pv1 will be the
+ # offset and pv2-pv1 will be the scale.
+
+ call aclrl (pv1, IM_MAXDIM)
+ call aclrl (lv, IM_MAXDIM)
+ call imaplv (im, lv, pv1, 2)
+ call amovkl (long(1), lv, IM_MAXDIM)
+ call aclrl (pv2, IM_MAXDIM)
+ call imaplv (im, lv, pv2, 2)
+
+ i = 1
+ axis[1] = 1; axis[2] = 2
+ do j = 1, IM_MAXDIM
+ if (pv1[j] != pv2[j]) {
+ axis[i] = j
+ i = i + 1
+ }
+
+ pv2[axis[1]] = (pv2[axis[1]] - pv1[axis[1]])
+ pv2[axis[2]] = (pv2[axis[2]] - pv1[axis[2]])
+
+ # These imply a new rotation matrix which we won't bother to work out
+ # separately here. Multiply the two rotation matrices and add the
+ # translation vectors to get the overall transformation from screen
+ # coordinates to image coordinates.
+ a = a * pv2[axis[1]]
+ d = d * pv2[axis[2]]
+ tx = tx * pv2[axis[1]] + pv1[axis[1]]
+ ty = ty * pv2[axis[2]] + pv1[axis[2]]
+
+ # Get the image name (minus image section) and
+ # title string (minus any newline.
+ call ds_gimage (im, image, Memc[imname], SZ_FNAME)
+ call strcpy (IM_TITLE(im), Memc[title], SZ_LINE)
+ for (ip=title; Memc[ip] != '\n' && Memc[ip] != EOS; ip=ip+1)
+ ;
+ Memc[ip] = EOS
+
+
+ # Define the mapping from the image pixels to frame buffer pixels.
+ src = W_WC(wdes,W_IPIX)
+ sx = W_XS(src)
+ sy = W_YS(src)
+ snx = (W_XE(src) - W_XS(src) + 1)
+ sny = (W_YE(src) - W_YS(src) + 1)
+
+ dest = W_WC(wdes,W_DPIX)
+ dx = W_XS(dest)
+ dy = W_YS(dest)
+ dnx = (W_XE(dest) - W_XS(dest) + 1)
+ dny = (W_YE(dest) - W_YS(dest) + 1)
+
+ # For a single image display the 'region' is fixed. The object ref
+ # is the fully defined image node!prefix path, including any sections.
+ # We need a special kludge to keep backward compatability with the
+ # use of "dev$pix" as the standard test image name.
+ call strcpy ("image", Memc[region], SZ_FNAME)
+ if (streq (image, "dev$pix"))
+ call fpathname ("dev$pix.imh", Memc[objref], SZ_PATHNAME)
+ else
+ call fpathname (image, Memc[objref], SZ_PATHNAME)
+
+ # Add the mapping info to be written with the WCS.
+ call imd_setmapping (Memc[region], sx, sy, snx, sny,
+ dx, dy, dnx, dny, Memc[objref])
+
+ # Write the WCS.
+ call imd_putwcs (ds, frame, Memc[imname], Memc[title],
+ a, b, c, d, tx, ty, W_ZS(wdwin), W_ZE(wdwin), W_ZT(wdwin))
+
+ call sfree (sp)
+end
+
+
+# DS_GIMAGE -- Convert input image section name to a 2D physical image section.
+
+procedure ds_gimage (im, input, output, maxchar)
+
+pointer im #I IMIO pointer
+char input[ARB] #I Input image name
+char output[maxchar] #O Output image name
+int maxchar #I Maximum characters in output name.
+
+int i, fd
+pointer sp, section, lv, pv1, pv2
+
+int stropen(), strlen()
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (section, SZ_FNAME, TY_CHAR)
+ call salloc (lv, IM_MAXDIM, TY_LONG)
+ call salloc (pv1, IM_MAXDIM, TY_LONG)
+ call salloc (pv2, IM_MAXDIM, TY_LONG)
+
+ # Get endpoint coordinates in original image.
+ call amovkl (long(1), Meml[lv], IM_MAXDIM)
+ call aclrl (Meml[pv1], IM_MAXDIM)
+ call imaplv (im, Meml[lv], Meml[pv1], 2)
+ call amovl (IM_LEN(im,1), Meml[lv], IM_NDIM(im))
+ call aclrl (Meml[pv2], IM_MAXDIM)
+ call imaplv (im, Meml[lv], Meml[pv2], 2)
+
+ # Set image section.
+ fd = stropen (Memc[section], SZ_FNAME, NEW_FILE)
+ call fprintf (fd, "[")
+ do i = 1, IM_MAXDIM {
+ if (Meml[pv1+i-1] != Meml[pv2+i-1])
+ call fprintf (fd, "*")
+ else if (Meml[pv1+i-1] != 0) {
+ call fprintf (fd, "%d")
+ call pargi (Meml[pv1+i-1])
+ } else
+ break
+ call fprintf (fd, ",")
+ }
+ call close (fd)
+ i = strlen (Memc[section])
+ Memc[section+i-1] = ']'
+
+ if (streq ("[*,*]", Memc[section]))
+ Memc[section] = EOS
+
+ # Strip existing image section and add new section.
+# call imgimage (input, output, maxchar)
+# call strcat (Memc[section], output, maxchar)
+
+ if (Memc[section] == EOS)
+ call imgimage (input, output, maxchar)
+ else
+ call strcpy (input, output, maxchar)
+
+ call sfree (sp)
+end
+
+
+# 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. All spatial scaling is
+# handled by the "scaled input" package, i.e., SIGM2[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_load_display (im, ds, wdes)
+
+pointer im # input image
+pointer ds # output image
+pointer wdes # graphics window descriptor
+
+real z1, z2, dz1, dz2, px1, px2, py1, py2
+int i, order, zt, wx1, wx2, wy1, wy2, wy, nx, ny, xblk, yblk, color
+pointer wdwin, wipix, wdpix, ovrly, bpm, pm, uptr
+pointer in, out, si, si_ovrly, si_bpovrly, ocolors, bpcolors, rtemp
+bool unitary_greyscale_transformation
+short lut1, lut2, dz1_s, dz2_s, z1_s, z2_s
+
+bool fp_equalr()
+int imstati(), maskcolor()
+pointer ds_pmmap(), imps2s(), imps2r()
+pointer sigm2s(), sigm2i(), sigm2r(), sigm2_setup()
+errchk ds_pmmap, imps2s, imps2r, sigm2s, sigm2i, sigm2r, sigm2_setup
+errchk maskexprn
+
+begin
+ wdwin = W_WC(wdes,W_DWIN)
+ wipix = W_WC(wdes,W_IPIX)
+ wdpix = W_WC(wdes,W_DPIX)
+
+ # Set image and display pixels.
+ px1 = nint (W_XS(wipix))
+ px2 = nint (W_XE(wipix))
+ py1 = nint (W_YS(wipix))
+ py2 = nint (W_YE(wipix))
+ wx1 = nint (W_XS(wdpix))
+ wx2 = nint (W_XE(wdpix))
+ wy1 = nint (W_YS(wdpix))
+ wy2 = nint (W_YE(wdpix))
+
+ z1 = W_ZS(wdwin)
+ z2 = W_ZE(wdwin)
+ zt = W_ZT(wdwin)
+ uptr = W_UPTR(wdwin)
+ order = max (W_XT(wdwin), W_YT(wdwin))
+
+ # Setup scaled input and masks.
+ si = NULL
+ si_ovrly = NULL
+ si_bpovrly = NULL
+ nx = wx2 - wx1 + 1
+ ny = wy2 - wy1 + 1
+ xblk = INDEFI
+ yblk = INDEFI
+
+ ocolors = W_OCOLORS(wdes)
+ iferr (ovrly = ds_pmmap (W_OVRLY(wdes), im)) {
+ call erract (EA_WARN)
+ ovrly = NULL
+ }
+ if (ovrly != NULL) {
+ xblk = INDEFI
+ yblk = INDEFI
+ si_ovrly = sigm2_setup (ovrly, NULL, px1,px2,nx,xblk,
+ py1,py2,ny,yblk, -1)
+ }
+
+ bpcolors = W_BPCOLORS(wdes)
+ switch (W_BPDISP(wdes)) {
+ case BPDNONE:
+ si = sigm2_setup (im, NULL, px1,px2,nx,xblk, py1,py2,ny,yblk, order)
+ case BPDOVRLY:
+ si = sigm2_setup (im, NULL, px1,px2,nx,xblk, py1,py2,ny,yblk, order)
+ iferr (bpm = ds_pmmap (W_BPM(wdes), im))
+ bpm = NULL
+ if (bpm != NULL)
+ si_bpovrly = sigm2_setup (bpm, NULL, px1,px2,nx,xblk,
+ py1,py2,ny,yblk, -1)
+ case BPDINTERP:
+ iferr (bpm = ds_pmmap (W_BPM(wdes), im))
+ bpm = NULL
+ if (bpm != NULL)
+ pm = imstati (bpm, IM_PMDES)
+ else
+ pm = NULL
+ si = sigm2_setup (im, pm, px1,px2,nx,xblk, py1,py2,ny,yblk, order)
+ }
+
+ # The device IM_MIN and IM_MAX parameters define the acceptable range
+ # of greyscale values for the output device (e.g., 0-255 for most 8-bit
+ # display devices). Values Z1 and Z2 are mapped linearly or
+ # logarithmically into IM_MIN and IM_MAX.
+
+ dz1 = IM_MIN(ds)
+ dz2 = IM_MAX(ds)
+ if (fp_equalr (z1, z2)) {
+ z1 = z1 - 1
+ z2 = z2 + 1
+ }
+
+ # If the user specifies the transfer function, verify that the
+ # intensity and greyscale are in range.
+
+ if (zt == W_USER) {
+ call alims (Mems[uptr], U_MAXPTS, 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 if (zt == W_LINEAR) {
+ unitary_greyscale_transformation =
+ (fp_equalr(z1,dz1) && fp_equalr(z2,dz2))
+ } else
+ unitary_greyscale_transformation = false
+
+ if (IM_PIXTYPE(im) == TY_SHORT && zt != W_LOG) {
+ z1_s = z1; z2_s = z2
+ if (z1_s == z2_s) {
+ z1_s = z1_s - 1
+ z2_s = z2_s + 1
+ }
+
+ for (wy=wy1; wy <= wy2; wy=wy+1) {
+ in = sigm2s (si, wy - wy1 + 1)
+ out = imps2s (ds, wx1, wx2, wy, wy)
+
+ if (unitary_greyscale_transformation) {
+ call amovs (Mems[in], Mems[out], nx)
+ } else if (zt == W_USER) {
+ dz1_s = U_Z1; dz2_s = U_Z2
+ call amaps (Mems[in],Mems[out],nx, z1_s,z2_s, dz1_s,dz2_s)
+ call aluts (Mems[out], Mems[out], nx, Mems[uptr])
+ } else {
+ dz1_s = dz1; dz2_s = dz2
+ call amaps (Mems[in],Mems[out],nx, z1_s,z2_s, dz1_s,dz2_s)
+ }
+
+ if (si_ovrly != NULL) {
+ in = sigm2i (si_ovrly, wy - wy1 + 1)
+ call maskexprn (ocolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (ocolors, Memi[in+i])
+ if (color >= 0)
+ Mems[out+i] = color
+ }
+ }
+ }
+ if (si_bpovrly != NULL) {
+ in = sigm2i (si_bpovrly, wy - wy1 + 1)
+ call maskexprn (bpcolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (bpcolors, Memi[in+i])
+ if (color >= 0)
+ Mems[out+i] = color
+ }
+ }
+ }
+ }
+
+ } else if (zt == W_USER) {
+ call salloc (rtemp, nx, TY_REAL)
+
+ for (wy=wy1; wy <= wy2; wy=wy+1) {
+ in = sigm2r (si, wy - wy1 + 1)
+ out = imps2s (ds, wx1, wx2, wy, wy)
+
+ call amapr (Memr[in], Memr[rtemp], nx, z1, z2,
+ real(U_Z1), real(U_Z2))
+ call achtrs (Memr[rtemp], Mems[out], nx)
+ call aluts (Mems[out], Mems[out], nx, Mems[uptr])
+
+ if (si_ovrly != NULL) {
+ in = sigm2i (si_ovrly, wy - wy1 + 1)
+ call maskexprn (ocolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (ocolors, Memi[in+i])
+ if (color >= 0)
+ Mems[out+i] = color
+ }
+ }
+ }
+ if (si_bpovrly != NULL) {
+ in = sigm2i (si_bpovrly, wy - wy1 + 1)
+ call maskexprn (bpcolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (bpcolors, Memi[in+i])
+ if (color >= 0)
+ Mems[out+i] = color
+ }
+ }
+ }
+ }
+
+ } else {
+ for (wy=wy1; wy <= wy2; wy=wy+1) {
+ in = sigm2r (si, wy - wy1 + 1)
+ out = imps2r (ds, wx1, wx2, wy, wy)
+
+ if (unitary_greyscale_transformation) {
+ call amovr (Memr[in], Memr[out], nx)
+ } else if (zt == W_LOG) {
+ call amapr (Memr[in], Memr[out], nx,
+ z1, z2, 1.0, 10.0 ** MAXLOG)
+ do i = 0, nx-1
+ Memr[out+i] = log10 (Memr[out+i])
+ call amapr (Memr[out], Memr[out], nx,
+ 0.0, real(MAXLOG), dz1, dz2)
+ } else
+ call amapr (Memr[in], Memr[out], nx, z1, z2, dz1, dz2)
+
+ if (si_ovrly != NULL) {
+ in = sigm2i (si_ovrly, wy - wy1 + 1)
+ call maskexprn (ocolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (ocolors, Memi[in+i])
+ if (color >= 0)
+ Memr[out+i] = color
+ }
+ }
+ }
+ if (si_bpovrly != NULL) {
+ in = sigm2i (si_bpovrly, wy - wy1 + 1)
+ call maskexprn (bpcolors, in, nx)
+ do i = 0, nx-1 {
+ if (Memi[in+i] != 0) {
+ color = maskcolor (bpcolors, Memi[in+i])
+ if (color >= 0)
+ Memr[out+i] = color
+ }
+ }
+ }
+ }
+ }
+
+ call sigm2_free (si)
+ if (si_ovrly != NULL)
+ call sigm2_free (si_ovrly)
+ if (si_bpovrly != NULL)
+ call sigm2_free (si_bpovrly)
+ if (ovrly != NULL)
+ call imunmap (ovrly)
+ if (bpm != NULL)
+ call imunmap (bpm)
+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, ds, wdes)
+
+pointer im # input image
+pointer ds # output image (display)
+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 i, nx
+pointer wdwin, wdpix
+pointer imps2s()
+errchk imps2s
+
+begin
+ wdwin = W_WC(wdes,W_DWIN)
+ wdpix = W_WC(wdes,W_DPIX)
+
+ # Set display pixels and display window pixels.
+ wx1 = nint (W_XS(wdpix))
+ wx2 = nint (W_XE(wdpix))
+ wy1 = nint (W_YS(wdpix))
+ wy2 = nint (W_YE(wdpix))
+ dx1 = max (1, nint (W_XS(wdwin)))
+ dx2 = min (IM_LEN(ds,1), nint (W_XE(wdwin) - 0.01))
+ dy1 = max (1, nint (W_YS(wdwin)))
+ dy2 = min (IM_LEN(ds,2), nint (W_YE(wdwin) - 0.01))
+ nx = dx2 - dx1 + 1
+
+ # Erase lower margin.
+ for (i=dy1; i < wy1; i=i+1)
+ call aclrs (Mems[imps2s (ds, dx1, dx2, i, i)], nx)
+
+ # 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.
+
+ for (i=wy1; i <= wy2; i=i+1) {
+ if (dx1 < wx1)
+ call aclrs (Mems[imps2s (ds, dx1, wx1-1, i, i)], wx1 - dx1)
+ if (wx2 < dx2)
+ call aclrs (Mems[imps2s (ds, wx2+1, dx2, i, i)], dx2 - wx2)
+ }
+
+ # Erase upper margin.
+ for (i=wy2+1; i <= dy2; i=i+1)
+ call aclrs (Mems[imps2s (ds, dx1, dx2, i, i)], nx)
+end