1////////////////////////////////////////////////////////////////////////////////////
2////////////////////////////////////////////////////////////////////////////////////
3Frame_item = class
4	Menupullright "Picture _Frame" "working with images of frames"
5	{
6	////////////////////////////////////////////////////////////////////////////////////
7	Build_frame_item = class
8	Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b"
9		{
10		////////////////////////////////////////////////////////////////////////////////////
11		Frame_corner_item = class
12			Menuaction "_Frame Corner"
13			"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b"
14			{
15			prefs = Workspaces.Preferences;
16
17			action a b = class
18				_result
19			{
20			_check_args = [
21				[a, "a", check_Image],
22				[b, "b", check_Image]
23				];
24			_check_all = [
25				[a.coding == b.coding && a.bands == b.bands,
26					"a.coding == b.coding && a.bands == b.bands"]
27				];
28			_vislevel = 3;
29
30			ppcm = Expression "Number of pixels per cm" 25;
31
32			/* Given the value of ppcm, distance between the inner edge of the frame
33			 * and the outer edge of the image.  +ve values mean the frame overlaps
34			 * the image.
35			 */
36			overlap = Expression "Size of frame overlap in cm" 0;
37			variables = class
38				{
39				scale_factor = Expression "scale the size of the frame by" 1;
40
41				/* These sliders define the fraction of the frames width or height is extracted
42		 		 * to produce each of the particular regions.
43		 		 */
44				corner_section = Slider 0.1 1 0.5;
45				middle_section = Slider 0.1 1 0.2;
46				blend_fraction = Slider 0.1 0.9 0.1;
47				}
48
49			_type = Image_type.colour_spaces.get_name b.type;
50
51			//If applied the count colour be seen for -ve values of overlap
52			mount_options = class
53				{
54				apply = Toggle "Apply mount options" false;
55				ls = Expression "Lower mount section bigger by (cm)" 0;
56				mount_colour = Colour _type [0, 0, 0];
57				_los = ls.expr * ppcm.expr;
58				}
59
60			_cs = variables.corner_section.value;
61			_ms = variables.middle_section.value;
62			_ov = ppcm.expr * overlap.expr;
63			_sf = variables.scale_factor.expr;
64			_bf = variables.blend_fraction.value;
65
66			//Scale frame image if required.
67			_a = a, _sf == 1;
68			   = a, _sf == 0;
69			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);
70
71			_im_w = b.width;
72			_im_h = b.height + mount_options._los, mount_options.apply
73				  = b.height;
74			_os = mount_options._los, mount_options.apply
75				= 0;
76			_cl = Vector mount_options.mount_colour.value, mount_options.apply
77				= 0;
78
79			//Produce scaled and resized frame.
80			frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf;
81			//Resize image canvas and applied mount colour as required.
82			_pos_im = frame_position_image b frame _os _cl;
83			//Wrap frame round image.
84			_result = if (frame == 0) then _pos_im else frame;
85			}
86			}
87
88		////////////////////////////////////////////////////////////////////////////////////
89		Simple_frame_item = class
90			Menuaction "_Simple Frame"
91				"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b"
92			{
93			prefs = Workspaces.Preferences;
94
95			action a b = class
96			_result
97			{
98			_check_args = [
99				[a, "a", check_Image],
100				[b, "b", check_Image]
101				];
102			_check_all = [
103				[a.coding == b.coding && a.bands == b.bands,
104					"a.coding == b.coding && a.bands == b.bands"]
105				];
106			_vislevel = 3;
107
108
109			ppcm = Expression "Number of pixels per cm" 25;
110
111			/* Given the value of ppcm, distance between the inner edge of the frame
112			 * and the outer edge of the image.  +ve values mean the frame overlaps
113			 * the image.
114			 */
115			overlap = Expression "Size of frame overlap in cm" 0;
116
117			variables = class
118				{
119				scale_factor = Expression "scale the size of the frame by" 1;
120
121				/* These sliders define the fraction of the frames width or height that
122				 * is extracted to produce each of the particular regions.
123		 		 */
124				corner_section = Slider 0.1 1 0.5;
125				middle_section = Slider 0.1 1 0.3;
126				blend_fraction = Slider 0.1 0.9 0.1;
127				option = Toggle "Use mirror of left-side to make right" true;
128				}
129
130			_type = Image_type.colour_spaces.get_name b.type;
131			//If applied the count colour be seen for -ve values of overlap
132			mount_options = class
133				{
134				apply = Toggle "Apply mount options" false;
135				ls = Expression "Lower mount section bigger by (cm)" 0;
136				mount_colour = Colour _type [0, 0, 0];
137				_los = ls.expr * ppcm.expr;
138				}
139
140			_cs = variables.corner_section.value;
141			_ms = variables.middle_section.value;
142			_ov = ppcm.expr * overlap.expr;
143			_sf = variables.scale_factor.expr;
144			_bf = variables.blend_fraction.value;
145
146			//Scale frame image if required.
147			_a = a, _sf == 1;
148			   = a, _sf == 0;
149			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);
150
151			_im_w = b.width;
152			_im_h = b.height + mount_options._los, mount_options.apply
153				  = b.height;
154			_os = mount_options._los, mount_options.apply
155				= 0;
156			_cl = Vector mount_options.mount_colour.value, mount_options.apply
157				= 0;
158
159			//Produce scaled and resized frame.
160			frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;
161			//Resize image canvas and applied mount colour as required.
162			_pos_im = frame_position_image b frame _os _cl;
163			//Wrap frame round image.
164			_result = if (frame == 0) then _pos_im else frame;
165			}
166			}
167
168		////////////////////////////////////////////////////////////////////////////////////
169		Complex_frame_item = class
170			Menuaction "_Complex Frame"
171			"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" {
172		prefs = Workspaces.Preferences;
173
174		action a b = class
175			_result
176			{
177			_check_args = [
178				[a, "a", check_Image],
179				[b, "b", check_Image]
180				];
181			_check_all = [
182				[a.coding == b.coding && a.bands == b.bands,
183					"a.coding == b.coding && a.bands == b.bands"]
184				];
185			_vislevel = 3;
186
187			ppcm = Expression "Number of pixels per cm" 25;
188
189			/* Given the value of ppcm, distance between the inner edge of the frame
190			 * and the outer edge of the image.  +ve values mean the frame overlaps
191			 * the image.
192			 */
193			overlap = Expression "Size of frame overlap in cm" 0;
194
195			variables = class
196				{
197				scale_factor = Expression "scale the size of the frame by" 1;
198
199				/* These sliders define the fraction of the frames width or height is extracted
200		 		 * to produce each of the particular regions.
201		 		 */
202				corner_section = Slider 0.1 1 0.4;
203				edge_section = Slider 0.1 1 0.1;
204				middle_section = Slider 0.1 0.5 0.3;
205				blend_fraction = Slider 0.1 0.9 0.1;
206				option = Toggle "Use mirror of left-side to make right" true;
207				}
208
209
210			_type = Image_type.colour_spaces.get_name b.type;
211
212			//If applied the count colour be seen for -ve values of overlap
213			mount_options = class
214				{
215				apply = Toggle "Apply mount color" false;
216				ls = Expression "Lower mount section bigger by (cm)" 0;
217				colour = Colour _type [0, 0, 0];
218				_los = ls.expr * ppcm.expr;
219				}
220
221			_cs = variables.corner_section.value;
222			_es = variables.edge_section.value;
223			_ms = variables.middle_section.value;
224			_ov = ppcm.expr * overlap.expr;
225			_sf = variables.scale_factor.expr;
226			_bf = variables.blend_fraction.value;
227
228			_a = a, _sf == 1;
229			   = a, _sf == 0;
230			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);
231
232			_im_w = b.width;
233			_im_h = b.height + mount_options._los, mount_options.apply
234				  = b.height;
235			_os = mount_options._los, mount_options.apply
236				= 0;
237			_cl = Vector mount_options.colour.value, mount_options.apply
238				= 0;
239
240
241			//Produce scaled and resized frame.
242			frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;
243			//Resize image canvas and applied mount colour as required.
244			_pos_im = frame_position_image b frame _os _cl;
245			//Wrap frame round image.
246			_result = if (frame == 0) then _pos_im else frame;
247			}
248		}
249	}
250////////////////////////////////////////////////////////////////////////////////////
251	Straighten_frame_item = class
252		Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" {
253		action a = Perspective_item.action a;
254		}
255};
256
257////////////////////////////////////////////////////////////////////////////////////
258////////////////////////////////////////////////////////////////////////////////////
259Select_item = class
260	Menupullright "_Select"
261		"select user defined areas of an image" {
262	prefs = Workspaces.Preferences;
263
264	/* Option toggle used to define whether the user is replacing a
265	 * dark or a light area.
266	 */
267	_control = Option "Make" [
268		"Selection Brighter",
269	 	"Selection Darker",
270	 	"Selection Black",
271	 	"Selection White",
272	 	"Background Black",
273	 	"Background White",
274		"Mask" ] 6;
275
276
277	control_selection mask im no
278		= (if mask then im * 1.2 else im * 1), no == 0
279		= (if mask then im * 0.8 else im * 1), no == 1
280		= (if mask then 0 else im), no == 2
281		= (if mask then 255 else im), no == 3
282		= (if mask then im else 0), no == 4
283		= (if mask then im else 255), no == 5
284		= mask;
285
286	Elipse = class
287		Menuaction "_Ellipse"
288			"use a line/arrow x to define the center point radius and direction of an ellipse"
289		{
290		action x = class
291			_result {
292			_vislevel = 3;
293
294			control = _control;
295			width = Slider 0.01 1 0.5;
296
297			_result = control_selection mask im control
298  				{
299				mask = select_ellipse x width.value;
300				im = x.image;
301				}
302			}
303		}
304
305	Tetragon = class
306		Menuaction "_Tetragon"
307			"selects the convex area defined by four points"
308		{
309		action a b c d = class
310			_result {
311			_vislevel = 3;
312
313			control = _control;
314
315			_result = control_selection mask im control
316				{
317				mask = select_tetragon a b c d;
318				im = a.image;
319				}
320			}
321
322		}
323
324	Polygon = class
325		Menuaction "_Polygon"
326			"selects a polygon from an ordered group of points"
327		{
328		action pt_list = class
329			_result {
330			_vislevel = 3;
331
332			control = _control;
333
334			_result = control_selection mask im control
335				{
336				mask = select_polygon pt_list;
337				im = ((pt_list.value)?0).image;
338				}
339			}
340		}
341	};
342////////////////////////////////////////////////////////////////////////////////////
343////////////////////////////////////////////////////////////////////////////////////
344
345Perspective_match_item = class
346	Menuaction "_Perspective Match"
347		"rotate, scale and skew one image to match another" {
348	action x y = class
349		_result {
350		_vislevel = 3;
351
352		// try to find an image ... for a group, get the first item
353		find_image x
354			= x, is_Image x
355			= find_image x?0, is_list x
356			= find_image x.value, is_class x && has_value x
357			= error "unable to find image";
358
359		_a = find_image x;
360		_b = find_image y;
361
362		ap1 = Mark_relative _a 0.1 0.1;
363		ap2 = Mark_relative _a 0.9 0.1;
364		ap3 = Mark_relative _a 0.1 0.9;
365		ap4 = Mark_relative _a 0.9 0.9;
366
367		bp1 = Mark_relative _b 0.1 0.1;
368		bp2 = Mark_relative _b 0.9 0.1;
369		bp3 = Mark_relative _b 0.1 0.9;
370		bp4 = Mark_relative _b 0.9 0.9;
371
372		_result = map_binary process x y
373			{
374			f1 = _a.width / _b.width;
375			f2 = _a.height / _b.height;
376
377			rl = sort_pts_clockwise [ap1, ap2, ap3, ap4];
378			pl = sort_pts_clockwise [bp1, bp2, bp3, bp4];
379
380			to = [
381				rl?0.left, rl?0.top,
382				rl?1.left, rl?1.top,
383				rl?2.left, rl?2.top,
384				rl?3.left, rl?3.top
385			];
386
387			from = [
388				pl?0.left * f1, pl?0.top * f2,
389				pl?1.left * f1, pl?1.top * f2,
390				pl?2.left * f1, pl?2.top * f2,
391				pl?3.left * f1, pl?3.top * f2
392			];
393
394			trans = perspective_transform to from;
395
396			process a b = transform 1 0 trans b2
397				{
398				b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)
399			    	= resize f1 1 1 b1
400					{b1 = resize 1 f2 1 b;}
401				}
402			}
403		}
404	}
405
406////////////////////////////////////////////////////////////////////////////////////
407////////////////////////////////////////////////////////////////////////////////////
408Perspective_item = class
409	Menuaction "Pe_rspective Distort"
410		"rotate, scale and skew an image with respect to defined points" {
411	action x = class
412		_result	{
413		_vislevel = 3;
414
415		// try to find an image ... for a group, get the first item
416		find_image x
417			= x, is_Image x
418			= find_image x?0, is_list x
419			= find_image x.value, is_class x && has_value x
420			= error "unable to find image";
421
422		_a = find_image x;
423
424		dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1;
425		ap1 = Mark_relative _a 0.1 0.1;
426		ap2 = Mark_relative _a 0.9 0.1;
427		ap3 = Mark_relative _a 0.9 0.9;
428		ap4 = Mark_relative _a 0.1 0.9;
429
430		_result = map_unary process x
431			{
432			trans = [perspective_transform to from, perspective_transform from to]?(dir.value)
433				{
434				rl = sort_pts_clockwise [ap1, ap2, ap3, ap4];
435				to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,
436			    	  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];
437				from=[0, 0, (_a.width - 1), 0,
438					  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];
439				}
440
441			process a = transform 1 0 trans a;
442			}
443		}
444	};
445
446