////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
Frame_item = class
	Menupullright "Picture _Frame" "working with images of frames"
	{
	////////////////////////////////////////////////////////////////////////////////////
	Build_frame_item = class
	Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b"
		{
		////////////////////////////////////////////////////////////////////////////////////
		Frame_corner_item = class
			Menuaction "_Frame Corner" 
			"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" 
			{
			prefs = Workspaces.Preferences;

			action a b = class
				_result
			{
			_check_args = [
				[a, "a", check_Image],
				[b, "b", check_Image]
				];
			_check_all = [
				[a.coding == b.coding && a.bands == b.bands,
					"a.coding == b.coding && a.bands == b.bands"]
				];
			_vislevel = 3;

			ppcm = Expression "Number of pixels per cm" 25;

			/* Given the value of ppcm, distance between the inner edge of the frame
			 * and the outer edge of the image.  +ve values mean the frame overlaps
			 * the image.
			 */
			overlap = Expression "Size of frame overlap in cm" 0;
			variables = class
				{
				scale_factor = Expression "scale the size of the frame by" 1;

				/* These sliders define the fraction of the frames width or height is extracted
		 		 * to produce each of the particular regions.
		 		 */
				corner_section = Scale "Corner section" 0.1 1 0.5;
				middle_section = Scale "Middle section" 0.1 1 0.2;
				blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1;
				}

			_type = Image_type.colour_spaces.get_name b.type;

			//If applied the count colour be seen for -ve values of overlap
			mount_options = class
				{
				apply = Toggle "Apply mount options" false;
				ls = Expression "Lower mount section bigger by (cm)" 0;
				mount_colour = Colour _type [0, 0, 0];
				_los = ls.expr * ppcm.expr;
				}

			_cs = variables.corner_section.value;
			_ms = variables.middle_section.value;
			_ov = ppcm.expr * overlap.expr;
			_sf = variables.scale_factor.expr;
			_bf = variables.blend_fraction.value;

			//Scale frame image if required.
			_a = a, _sf == 1;
			   = a, _sf == 0;
			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);

			_im_w = b.width;
			_im_h = b.height + mount_options._los, mount_options.apply
				  = b.height;
			_os = mount_options._los, mount_options.apply
				= 0;
			_cl = Vector mount_options.mount_colour.value, mount_options.apply
				= 0;

			//Produce scaled and resized frame.
			frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf;
			//Resize image canvas and applied mount colour as required.
			_pos_im = frame_position_image b frame _os _cl;
			//Wrap frame round image.
			_result = if (frame == 0) then _pos_im else frame;
			}
			}
		
		////////////////////////////////////////////////////////////////////////////////////
		Simple_frame_item = class
			Menuaction "_Simple Frame" 
				"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b"
			{
			prefs = Workspaces.Preferences;

			action a b = class
			_result
			{
			_check_args = [
				[a, "a", check_Image],
				[b, "b", check_Image]
				];
			_check_all = [
				[a.coding == b.coding && a.bands == b.bands,
					"a.coding == b.coding && a.bands == b.bands"]
				];
			_vislevel = 3;


			ppcm = Expression "Number of pixels per cm" 25;

			/* Given the value of ppcm, distance between the inner edge of the frame
			 * and the outer edge of the image.  +ve values mean the frame overlaps
			 * the image.
			 */
			overlap = Expression "Size of frame overlap in cm" 0;

			variables = class
				{
				scale_factor = Expression "scale the size of the frame by" 1;

				/* These sliders define the fraction of the frames width or height that
				 * is extracted to produce each of the particular regions.
		 		 */
				corner_section = Scale "Corner section" 0.1 1 0.5;
				middle_section = Scale "Middle section" 0.1 1 0.2;
				blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1;
				option = Toggle "Use mirror of left-side to make right" true;
				}

			_type = Image_type.colour_spaces.get_name b.type;
			//If applied the count colour be seen for -ve values of overlap
			mount_options = class
				{
				apply = Toggle "Apply mount options" false;
				ls = Expression "Lower mount section bigger by (cm)" 0;
				mount_colour = Colour _type [0, 0, 0];
				_los = ls.expr * ppcm.expr;
				}

			_cs = variables.corner_section.value;
			_ms = variables.middle_section.value;
			_ov = ppcm.expr * overlap.expr;
			_sf = variables.scale_factor.expr;
			_bf = variables.blend_fraction.value;

			//Scale frame image if required.
			_a = a, _sf == 1;
			   = a, _sf == 0;
			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);

			_im_w = b.width;
			_im_h = b.height + mount_options._los, mount_options.apply
				  = b.height;
			_os = mount_options._los, mount_options.apply
				= 0;
			_cl = Vector mount_options.mount_colour.value, mount_options.apply
				= 0;

			//Produce scaled and resized frame.
			frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;
			//Resize image canvas and applied mount colour as required.
			_pos_im = frame_position_image b frame _os _cl;
			//Wrap frame round image.
			_result = if (frame == 0) then _pos_im else frame;
			}
			}
		
		////////////////////////////////////////////////////////////////////////////////////
		Complex_frame_item = class
			Menuaction "_Complex Frame" 
			"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" {
		prefs = Workspaces.Preferences;

		action a b = class
			_result
			{
			_check_args = [
				[a, "a", check_Image],
				[b, "b", check_Image]
				];
			_check_all = [
				[a.coding == b.coding && a.bands == b.bands,
					"a.coding == b.coding && a.bands == b.bands"]
				];
			_vislevel = 3;

			ppcm = Expression "Number of pixels per cm" 25;

			/* Given the value of ppcm, distance between the inner edge of the frame
			 * and the outer edge of the image.  +ve values mean the frame overlaps
			 * the image.
			 */
			overlap = Expression "Size of frame overlap in cm" 0;

			variables = class
				{
				scale_factor = Expression "scale the size of the frame by" 1;

				/* These sliders define the fraction of the frames width or height is extracted
		 		 * to produce each of the particular regions.
		 		 */
				corner_section = Scale "Corner section" 0.1 1 0.5;
				edge_section = Scale "Edge section" 0.1 1 0.2;
				middle_section = Scale "Middle section" 0.1 1 0.2;
				blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1;
				option = Toggle "Use mirror of left-side to make right" true;
				}


			_type = Image_type.colour_spaces.get_name b.type;

			//If applied the count colour be seen for -ve values of overlap
			mount_options = class
				{
				apply = Toggle "Apply mount color" false;
				ls = Expression "Lower mount section bigger by (cm)" 0;
				colour = Colour _type [0, 0, 0];
				_los = ls.expr * ppcm.expr;
				}

			_cs = variables.corner_section.value;
			_es = variables.edge_section.value;
			_ms = variables.middle_section.value;
			_ov = ppcm.expr * overlap.expr;
			_sf = variables.scale_factor.expr;
			_bf = variables.blend_fraction.value;

			_a = a, _sf == 1;
			   = a, _sf == 0;
			   = Image (resize _sf _sf Interpolate.BILINEAR a.value);

			_im_w = b.width;
			_im_h = b.height + mount_options._los, mount_options.apply
				  = b.height;
			_os = mount_options._los, mount_options.apply
				= 0;
			_cl = Vector mount_options.colour.value, mount_options.apply
				= 0;


			//Produce scaled and resized frame.
			frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;
			//Resize image canvas and applied mount colour as required.
			_pos_im = frame_position_image b frame _os _cl;
			//Wrap frame round image.
			_result = if (frame == 0) then _pos_im else frame;
			}
		}
	}	
////////////////////////////////////////////////////////////////////////////////////	
	Straighten_frame_item = class
		Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" {
		action a = Perspective_item.action a;
		}
};

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
Select_item = class
	Menupullright "_Select"
		"select user defined areas of an image" {
	prefs = Workspaces.Preferences;

	/* Option toggle used to define whether the user is replacing a
	 * dark or a light area.
	 */
	_control = Option "Make" [
		"Selection Brighter",
	 	"Selection Darker",
	 	"Selection Black",
	 	"Selection White",
	 	"Background Black",
	 	"Background White",
		"Mask" ] 6;


	control_selection mask im no
		= (if mask then im * 1.2 else im * 1), no == 0
		= (if mask then im * 0.8 else im * 1), no == 1
		= (if mask then 0 else im), no == 2
		= (if mask then 255 else im), no == 3
		= (if mask then im else 0), no == 4
		= (if mask then im else 255), no == 5
		= mask;

	Elipse = class
		Menuaction "_Ellipse"
			"use a line/arrow x to define the center point radius and direction of an ellipse"
		{
		action x = class
			_result {
			_vislevel = 3;

			control = _control;
			width = Scale "Width" 0.01 1 0.5;

			_result = control_selection mask im control
  				{
				mask = select_ellipse x width.value;
				im = x.image;
				}
			}
		}

	Tetragon = class
		Menuaction "_Tetragon"
			"selects the convex area defined by four points"
		{
		action a b c d = class
			_result {
			_vislevel = 3;

			control = _control;

			_result = control_selection mask im control
				{
				mask = select_tetragon a b c d;
				im = a.image;
				}
			}

		}

	Polygon = class
		Menuaction "_Polygon"
			"selects a polygon from an ordered group of points"
		{
		action pt_list = class
			_result {
			_vislevel = 3;

			control = _control;

			_result = control_selection mask im control
				{
				mask = select_polygon pt_list;
				im = ((pt_list.value)?0).image;
				}
			}
		}

	sep1 = Menuseparator;

	Threshold_item = class 
		Menuaction "Thres_hold" "simple image threshold" {
		action x = class 
			_result {
			_vislevel = 3;

			t 
				= Scale "Threshold" 0 mx (mx / 2)
			{
				mx 
					= Image_format.maxval x.format, is_Image x
					= 255;
			}

			_result = map_unary (more t.value) x;
		}
	}

	Threshold_percent_item = class 
		Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" {
		action x = class 
			_result {
			_vislevel = 3;

			t = Scale "Percentage of pixels" 0 100 50;

			_result 
				= map_unary (more (hist_thresh (t.value / 100) x)) x;
		}
	}

	};
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Perspective_match_item = class
	Menuaction "_Perspective Match" 
		"rotate, scale and skew one image to match another" {
	action x y = class
		_result {
		_vislevel = 3;

		// try to find an image ... for a group, get the first item
		find_image x
			= x, is_Image x
			= find_image x?0, is_list x
			= find_image x.value, is_class x && has_value x
			= error "unable to find image";

		_a = find_image x;
		_b = find_image y;

		ap1 = Mark_relative _a 0.1 0.1;
		ap2 = Mark_relative _a 0.9 0.1;
		ap3 = Mark_relative _a 0.1 0.9;
		ap4 = Mark_relative _a 0.9 0.9;
			
		bp1 = Mark_relative _b 0.1 0.1;
		bp2 = Mark_relative _b 0.9 0.1;
		bp3 = Mark_relative _b 0.1 0.9;
		bp4 = Mark_relative _b 0.9 0.9;

		_result = map_binary process x y
			{
			f1 = _a.width / _b.width;
			f2 = _a.height / _b.height;

			rl = sort_pts_clockwise [ap1, ap2, ap3, ap4];
			pl = sort_pts_clockwise [bp1, bp2, bp3, bp4];

			to = [
				rl?0.left, rl?0.top, 
				rl?1.left, rl?1.top,
				rl?2.left, rl?2.top, 
				rl?3.left, rl?3.top
			];

			from = [
				pl?0.left * f1, pl?0.top * f2, 
				pl?1.left * f1, pl?1.top * f2,
				pl?2.left * f1, pl?2.top * f2, 
				pl?3.left * f1, pl?3.top * f2
			];
			
			trans = perspective_transform to from;
			
			process a b = transform 1 0 trans b2
				{
				b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)
			    	= resize f1 1 1 b1
					{b1 = resize 1 f2 1 b;}
				}
			}
		}
	}
	
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
Perspective_item = class
	Menuaction "Pe_rspective Distort"
		"rotate, scale and skew an image with respect to defined points" {
	action x = class
		_result	{
		_vislevel = 3;

		// try to find an image ... for a group, get the first item
		find_image x
			= x, is_Image x
			= find_image x?0, is_list x
			= find_image x.value, is_class x && has_value x
			= error "unable to find image";

		_a = find_image x;

		dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1;
		ap1 = Mark_relative _a 0.1 0.1;
		ap2 = Mark_relative _a 0.9 0.1;
		ap3 = Mark_relative _a 0.9 0.9;
		ap4 = Mark_relative _a 0.1 0.9;
		
		_result = map_unary process x
			{			
			trans = [perspective_transform to from, perspective_transform from to]?(dir.value)
				{
				rl = sort_pts_clockwise [ap1, ap2, ap3, ap4];
				to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,
			    	  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];
				from=[0, 0, (_a.width - 1), 0, 
					  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];
				}

			process a = transform 1 0 trans a;
			}
		}
	};

