aboutsummaryrefslogtreecommitdiff
path: root/pkg/images/tv/iis/src/load2.x
blob: 5372907fb88604be086494b48eaa762db64d120a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
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