1/*
2
3   ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net).
4   1-Apr-2014
5     Minor corrections to Geometry_widget and Alpha.
6     Added loads of widgets and Menuactions.
7     Not fully tested.
8   5-Apr-2014
9     Many more menu actions.
10     Reorganised Magick menu.
11   10-Apr-2014
12     Many more menu actions.
13   11-Apr-2014 jcupitt
14     Split to separate Magick.def
15   13-Apr-2014 snibgo
16     Put "new image" items into sub-menu.
17     New class VirtualPixlBack.
18   17-Apr-2014 snibgo
19     Many small changes.
20     A few new menu options.
21     Created sub-menu for multi-input operations.
22   3-May-2014 jcupitt
23     Put quotes around ( in shadow to help unix
24
25   Last update: 17-Apr-2014.
26
27   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.
28*/
29
30// We don't need Noop.
31/*===
32Magick_noop_item = class
33	Menuaction "_Noop" "no operation" {
34	action x = class
35		_result {
36		_vislevel = 3;
37
38		command = Magick.command [
39			"\"%s\"",
40			"\"%s\""
41		];
42
43		_result = Magick.system command x;
44	}
45}
46===*/
47
48Magick_testPar_item = class
49	Menuaction "_TestPar" "no operation" {
50	action x = class
51		_result {
52		_vislevel = 3;
53
54		command = Magick.command [
55			"\"%s\"",
56			"( +clone ) +append ",
57			"\"%s\""
58		];
59
60		_result = Magick.system command x;
61	}
62}
63
64/* Removed Read_item and Write_item, much better to use nip2 load/save image.
65 * Plus they can load all libMagick formats anyway.
66 */
67
68
69// Put "new image" items into sub-menu
70Magick_NewImageMenu_item = class
71	Menupullright "_New image" "make a new image" {
72
73	Magick_newcanvas_item = class
74		Menuaction "_Solid colour" "make image of solid colour" {
75		action = class
76			_result {
77			_vislevel = 3;
78
79			size = Magick.Size_widget;
80			colour = Magick.generalcol_widget;
81			command = Magick.command [
82				size._flag,
83				"\"canvas:" ++ colour._flag ++ "\"",
84				"\"%s\""
85			];
86
87			_result = Magick.system0 command;
88		}
89	}
90
91	Magick_builtin_item = class
92		Menuaction "_Built-in image" "create a built-in image" {
93		action = class
94			_result {
95			_vislevel = 3;
96
97			builtin = Magick.builtin_widget;
98			command = Magick.command [
99				builtin._flag,
100				"\"%s\""
101			];
102
103			_result = Magick.system0 command;
104		}
105	}
106
107	Magick_gradient_item = class
108		Menuaction "_Gradient" "make a linear gradient between two colours" {
109		action = class
110			_result {
111			_vislevel = 3;
112
113			size = Magick.Size_widget;
114			topColour = Magick.generalcol_widget;
115			bottomColour = Magick.generalcol_widget;
116
117			command = Magick.command [
118				size._flag,
119				concat ["\"gradient:",
120					topColour._flag, "-", bottomColour._flag, "\""],
121				"\"%s\""
122			];
123
124			_result = Magick.system0 command;
125		}
126	}
127
128	Magick_hald_item = class
129		Menuaction "_Hald-clut image" "create an identity hald-clut image" {
130		action = class
131			_result {
132			_vislevel = 3;
133
134			order = Expression "order" 8;
135			command = Magick.command [
136				"hald:" ++ print order.expr,
137				"\"%s\""
138			];
139
140			_result = Magick.system0 command;
141		}
142	}
143
144	Magick_pattern_item = class
145		Menuaction "_Pattern" "create pattern" {
146		action = class
147			_result {
148			_vislevel = 3;
149
150			size = Magick.Size_widget;
151			pattern = Magick.pattern_widget;
152			command = Magick.command [
153				size._flag,
154				pattern._flag,
155				"\"%s\""
156			];
157
158			_result = Magick.system0 command;
159		}
160	}
161
162	Magick_plasma_item = class
163		Menuaction "_Plasma image" "create plasma image" {
164		action = class
165			_result {
166			_vislevel = 3;
167
168			size = Magick.Size_widget;
169			// FIXME? ColourA-ColourB.
170			// FIXME? Allow plasma:fractal?
171
172			command = Magick.command [
173				size._flag,
174				"plasma:",
175				"\"%s\""
176			];
177
178			_result = Magick.system0 command;
179		}
180	}
181
182	Magick_radialgradient_item = class
183		Menuaction "_Radial gradient"
184			"make a radial gradient between two colours" {
185		action = class
186			_result {
187			_vislevel = 3;
188
189			size = Magick.Size_widget;
190			innerColour = Magick.generalcol_widget;
191			outerColour = Magick.generalcol_widget;
192
193			command = Magick.command [
194				size._flag,
195				concat ["\"radial-gradient:",
196					innerColour._flag, "-", outerColour._flag, "\""],
197				"\"%s\""
198			];
199
200			_result = Magick.system0 command;
201		}
202	}
203}  // end Magick_NewImageMenu_item
204
205
206Magick_MultiMenu_item = class
207	Menupullright "_Multiple inputs" "make an image from multiple images" {
208
209	Magick_composite_item = class
210		Menuaction "_Composite" "composite two images (without mask)" {
211		action x y = class
212			_result {
213			_vislevel = 3;
214
215			method = Magick.compose_widget;
216			offsets = Magick.OffsetGeometry_widget;
217			gravity = Magick.gravity_widget;
218
219			command = Magick.command [
220				"\"%s\"",
221				"\"%s\"",
222				"-geometry", offsets._flag,
223				gravity._flag,
224				method._flag,
225				"-composite",
226				"\"%s\""
227			];
228
229			_result = Magick.system2 command x y;
230		}
231	}
232
233	Magick_compositeMask_item = class
234		Menuaction "_Composite masked" "composite two images (with mask)" {
235		action x y z = class
236			_result {
237			_vislevel = 3;
238
239			method = Magick.compose_widget;
240			offsets = Magick.OffsetGeometry_widget;
241			gravity = Magick.gravity_widget;
242
243			command = Magick.command [
244				"\"%s\"",
245				"\"%s\"",
246				"\"%s\"",
247				"-geometry", offsets._flag,
248				gravity._flag,
249				method._flag,
250				"-composite",
251				"\"%s\""
252			];
253
254			_result = Magick.system3 command x y z;
255		}
256	}
257
258	// FIXME: other operations like remap that take another image as arguments are:
259	// mask (pointless?), texture, tile (pointless?)
260
261	// FIXME: operations that take a filename that isn't an image:
262	// cdl, profile
263
264	Magick_clut_item = class
265		Menuaction "_Clut" "replace values using second image as colour look-up table" {
266		action x y = class
267			_result {
268			_vislevel = 3;
269
270			// FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels"
271
272			command = Magick.command [
273				"\"%s\"",
274				"\"%s\"",
275				"-clut",
276				"\"%s\""
277			];
278
279			_result = Magick.system2 command x y;
280		}
281	}
282
283	Magick_haldclut_item = class
284		Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" {
285		action x y = class
286			_result {
287			_vislevel = 3;
288
289			command = Magick.command [
290				"\"%s\"",
291				"\"%s\"",
292				"-hald-clut",
293				"\"%s\""
294			];
295
296			_result = Magick.system2 command x y;
297		}
298	}
299
300
301	// Encipher and decipher: key files can be text or image files.
302
303	Magick_encipher_item = class
304		Menuaction "_Encipher/Decipher" "encipher or decipher an image image" {
305		action x = class
306			_result {
307			_vislevel = 3;
308
309			pathname = Pathname "Read key file" "";
310			isDecipher = Toggle "Decipher" false;
311
312			command = Magick.command [
313				"\"%s\"",
314				if pathname.value == "" then "" else (
315					( if isDecipher then "-decipher " else "-encipher ") ++
316					( "\"" ++ pathname.value ++ "\"" )
317				),
318				"\"%s\""
319			];
320
321			_result = Magick.system command x;
322		}
323	}
324
325	Magick_profile_item = class
326		Menuaction "_Profile" "assigns/applies an ICC profile" {
327		action x = class
328			_result {
329			_vislevel = 3;
330
331			pathname1 = Pathname "Read profile file" "";
332			pathname2 = Pathname "Read profile file" "";
333
334			command = Magick.command [
335				"\"%s\"",
336				if pathname1.value == "" then "" else (
337					"-profile " ++
338					"\"" ++ pathname1.value ++ "\""),
339				if pathname2.value == "" then "" else (
340					"-profile " ++
341					"\"" ++ pathname2.value ++ "\""),
342				"\"%s\""
343			];
344
345			_result = Magick.system command x;
346		}
347	}
348
349	Magick_remap_item = class
350		Menuaction "_Remap" "reduce colours to those in another image" {
351		action x y = class
352			_result {
353			_vislevel = 3;
354
355			command = Magick.command [
356				"\"%s\"",
357				"-remap",
358				"\"%s\"",
359				"\"%s\""
360			];
361
362			_result = Magick.system2 command x y;
363		}
364	}
365
366}  // end Magick_MultiMenu_item
367
368
369Magick_image_type_item = class
370	Menuaction "_Image Type" "change image type" {
371	action x = class
372		_result {
373		_vislevel = 3;
374
375		imagetype = Magick.imagetype_widget;
376
377		command = Magick.command [
378			"\"%s\"",
379			imagetype._flag,
380			"\"%s\""
381		];
382
383		_result = Magick.system command x;
384	}
385}
386
387sep2 = Menuseparator;
388
389Magick_alpha_item = class
390	Menuaction "_Alpha" "add/remove alpha channel" {
391	action x = class
392		_result {
393		_vislevel = 3;
394
395		alpha = Magick.alpha_widget;
396		command = Magick.command [
397			"\"%s\"",
398			alpha._flag,
399			"\"%s\""
400		];
401
402		_result = Magick.system command x;
403	}
404}
405
406Magick_annotate_item = class
407	Menuaction "_Annotate" "add text annotation" {
408	action x = class
409		_result {
410		_vislevel = 3;
411
412		text = Magick.text_widget;
413		font = Magick.Font_widget;
414		geometry = Magick.AnnotGeometry_widget;
415		gravity = Magick.gravity_widget;
416		foreground = Magick.foreground_widget;
417		undercol = Magick.undercol_widget;
418		antialias = Magick.antialias_widget;
419		command = Magick.command [
420			"\"%s\"",
421			font._flag,
422			antialias._flag,
423			gravity._flag,
424			foreground._flag,
425			undercol._flag,
426			"-annotate",
427			geometry._flag,
428			"\"" ++ text.value ++ "\"",
429			"\"%s\""
430		];
431
432		_result = Magick.system command x;
433	}
434}
435
436Magick_autoGamma_item = class
437	Menuaction "_AutoGamma" "automatic gamma" {
438	action x = class
439		_result {
440		_vislevel = 3;
441
442		channels = Magick.channels_widget;
443		command = Magick.command [
444			"\"%s\"",
445			channels._flag,
446			"-auto-gamma",
447			"\"%s\""
448		];
449
450		_result = Magick.system command x;
451	}
452}
453
454Magick_autoLevel_item = class
455	Menuaction "_AutoLevel" "automatic level" {
456	action x = class
457		_result {
458		_vislevel = 3;
459
460		channels = Magick.channels_widget;
461		command = Magick.command [
462			"\"%s\"",
463			channels._flag,
464			"-auto-level",
465			"\"%s\""
466		];
467
468		_result = Magick.system command x;
469	}
470}
471
472Magick_blurSharpMenu_item = class
473	Menupullright "_Blur/Sharpen" "blur and sharpen" {
474
475	Magick_adaptive_blur_item = class
476		Menuaction "_Adaptive Blur" "blur less near edges" {
477		action x = class
478			_result {
479			_vislevel = 3;
480
481			intensity = Magick.intensity_widget;
482			radius = Magick.blur_rad_widget;
483			sigma = Magick.sigma_widget;
484			channels = Magick.channels_widget;
485			// note: adaptive-blur doesn't regard VP.
486
487			command = Magick.command [
488				"\"%s\"",
489				intensity._flag,
490				channels._flag,
491				"-adaptive-blur",
492				print radius.value ++ "x" ++ print sigma.value,
493				"\"%s\""
494			];
495
496			_result = Magick.system command x;
497		}
498	}
499
500	Magick_blur_item = class
501		Menuaction "_Blur" "blur" {
502		action x = class
503			_result {
504			_vislevel = 3;
505
506			radius = Magick.blur_rad_widget;
507			sigma = Magick.sigma_widget;
508			channels = Magick.channels_widget;
509			virtpixback = Magick.VirtualPixelBack_widget;
510			command = Magick.command [
511				"\"%s\"",
512				virtpixback._flag,
513				channels._flag,
514				"-blur",
515				print radius.value ++ "x" ++ print sigma.value,
516				"\"%s\""
517			];
518
519			_result = Magick.system command x;
520		}
521	}
522
523	Magick_gaussianBlur_item = class
524		Menuaction "_Gaussian Blur" "blur with a Gaussian operator" {
525		action x = class
526			_result {
527			_vislevel = 3;
528
529			radius = Magick.blur_rad_widget;
530			sigma = Magick.sigma_widget;
531			channels = Magick.channels_widget;
532			virtpixback = Magick.VirtualPixelBack_widget;
533			command = Magick.command [
534				"\"%s\"",
535				virtpixback._flag,
536				channels._flag,
537				"-gaussian-blur",
538				print radius.value ++ "x" ++ print sigma.value,
539				"\"%s\""
540			];
541
542			_result = Magick.system command x;
543		}
544	}
545
546	Magick_motionBlur_item = class
547		Menuaction "_Motion Blur" "simulate motion blur" {
548		action x = class
549			_result {
550			_vislevel = 3;
551
552			radius = Magick.blur_rad_widget;
553			sigma = Magick.sigma_widget;
554			angle = Scale "angle" (-360) 360 0;
555			channels = Magick.ch_widget;
556			virtpixback = Magick.VirtualPixelBack_widget;
557			command = Magick.command [
558				"\"%s\"",
559				virtpixback._flag,
560				channels._flag,
561				"-motion-blur",
562				print radius.value ++ "x" ++
563					print sigma.value ++ "+" ++
564					print angle.value,
565				"\"%s\""
566			];
567
568			_result = Magick.system command x;
569		}
570	}
571
572	Magick_rotationalBlur_item = class
573		Menuaction "_RotationalBlur" "blur around the centre" {
574		action x = class
575			_result {
576			_vislevel = 3;
577
578			channels = Magick.channels_widget;
579			virtpixback = Magick.VirtualPixelBack_widget;
580			angle = Scale "angle (degrees)" (-360) 360 20;
581
582			command = Magick.command [
583				"\"%s\"",
584				virtpixback._flag,
585				channels._flag,
586				"-radial-blur",
587				print angle.value,
588				"\"%s\""
589			];
590
591			_result = Magick.system command x;
592		}
593	}
594
595	Magick_selectiveBlur_item = class
596		Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" {
597		action x = class
598			_result {
599			_vislevel = 3;
600
601			intensity = Magick.intensity_widget;
602			radius = Magick.blur_rad_widget;
603			sigma = Magick.sigma_widget;
604			threshold = Scale "Threshold (percent)" 0 100 50;
605			channels = Magick.channels_widget;
606			virtpixback = Magick.VirtualPixelBack_widget;
607			command = Magick.command [
608				"\"%s\"",
609				intensity._flag,
610				virtpixback._flag,
611				channels._flag,
612				"-selective-blur",
613				print radius.value ++ "x" ++
614					print sigma.value ++  "+" ++
615					print threshold.value ++ "%%",
616				"\"%s\""
617			];
618
619			_result = Magick.system command x;
620		}
621	}
622
623	sep1 = Menuseparator;
624
625	Magick_adaptive_sharpen_item = class
626		Menuaction "_Adaptive Sharpen" "sharpen more near edges" {
627		action x = class
628			_result {
629			_vislevel = 3;
630
631			intensity = Magick.intensity_widget;
632			radius = Magick.blur_rad_widget;
633			sigma = Magick.sigma_widget;
634
635			command = Magick.command [
636				"\"%s\"",
637				intensity._flag,
638				"-adaptive-sharpen",
639				print radius.value ++ "x" ++ print sigma.value,
640				"\"%s\""
641			];
642
643			_result = Magick.system command x;
644		}
645	}
646
647	Magick_sharpen_item = class
648		Menuaction "_Sharpen" "sharpen" {
649		action x = class
650			_result {
651			_vislevel = 3;
652
653			radius = Magick.blur_rad_widget;
654			sigma = Magick.sigma_widget;
655			channels = Magick.channels_widget;
656			virtpixback = Magick.VirtualPixelBack_widget;
657			command = Magick.command [
658				"\"%s\"",
659				virtpixback._flag,
660				channels._flag,
661				"-sharpen",
662				print radius.value ++ "x" ++ print sigma.value,
663				"\"%s\""
664			];
665
666			_result = Magick.system command x;
667		}
668	}
669
670	Magick_unsharpen_item = class
671		Menuaction "_Unsharp" "sharpen with unsharp mask" {
672		action x = class
673			_result {
674			_vislevel = 3;
675
676			radius = Magick.blur_rad_widget;
677			sigma = Magick.sigma_widget;
678			channels = Magick.channels_widget;
679			gain = Scale "Gain" (-10) 10 1;
680			threshold = Scale "Threshold" 0 1 0.05;
681			virtpixback = Magick.VirtualPixelBack_widget;
682
683			command = Magick.command [
684				"\"%s\"",
685				virtpixback._flag,
686				channels._flag,
687				"-unsharp",
688				print radius.value ++ "x" ++
689					print sigma.value ++ "+" ++
690					print gain.value ++ "+" ++
691					print threshold.value,
692				"\"%s\""
693			];
694
695			_result = Magick.system command x;
696		}
697	}
698
699} // end BlurSharpMenu_item
700
701
702Magick_border_item = class
703	Menuaction "_Border" "add border of given colour" {
704	action x = class
705		_result {
706		_vislevel = 3;
707
708		compose = Magick.compose_widget;
709		width = Expression "Width" 3;
710		bordercol = Magick.bordercol_widget;
711
712		command = Magick.command [
713			"\"%s\"",
714			compose._flag,
715			bordercol._flag,
716			"-border",
717			print width.expr,
718			"\"%s\""
719		];
720
721		_result = Magick.system command x;
722	}
723}
724
725Magick_brightCont_item = class
726	Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" {
727	action x = class
728		_result {
729		_vislevel = 3;
730
731		bri = Scale "brightness" (-100) 100 0;
732		con = Scale "contrast" (-100) 100 0;
733		channels = Magick.channels_widget;
734
735		command = Magick.command [
736			"\"%s\"",
737			channels._flag,
738			"-brightness-contrast",
739			print bri.value ++ "x" ++ print con.value,
740			"\"%s\""
741		];
742
743		_result = Magick.system command x;
744	}
745}
746
747// Note: canny requires ImageMagick 6.8.9-0 or later.
748
749Magick_canny_item = class
750	Menuaction "_Canny" "detect a wide range of edges" {
751	action x = class
752		_result {
753		_vislevel = 3;
754
755		radius = Magick.blur_rad_widget;
756		sigma = Magick.sigma_widget;
757		lowPc = Scale "lower percent" 0 100 10;
758		highPc = Scale "lower percent" 0 100 10;
759
760		command = Magick.command [
761			"\"%s\"",
762			"-canny",
763			concat ["\"",
764				print radius.value ++ "x" ++
765				print sigma.value ++ "+" ++
766				print lowPc.value ++ "%%+" ++
767				print highPc.value ++ "%%" ++ "\""
768			],
769			"\"%s\""
770		];
771
772		_result = Magick.system command x;
773	}
774}
775
776
777Magick_charcoal_item = class
778	Menuaction "_Charcoal" "simulate a charcoal drawing" {
779	action x = class
780		_result {
781		_vislevel = 3;
782
783		intensity = Magick.intensity_widget;
784		factor = Scale "factor" 0 50 1;
785
786		command = Magick.command [
787			"\"%s\"",
788			intensity._flag,
789			"-charcoal",
790			print factor.value,
791			"\"%s\""
792		];
793
794		_result = Magick.system command x;
795	}
796}
797
798Magick_chop_item = class
799	Menuaction "_Chop" "remove pixels from the interior" {
800	action x = class
801		_result {
802		_vislevel = 3;
803
804		gravity = Magick.gravity_widget;
805		geometry = Magick.WhxyGeometry_widget;
806
807		command = Magick.command [
808			"\"%s\"",
809			gravity._flag,
810			"-chop",
811			geometry._flag,
812			"\"%s\""
813		];
814
815		_result = Magick.system command x;
816	}
817}
818
819Magick_colorize_item = class
820	Menuaction "_Colorize" "colorize by given amount" {
821	action x = class
822		_result {
823		_vislevel = 3;
824
825		foreground = Magick.foreground_widget;
826		val = Scale "value" 0 100 100;
827
828		command = Magick.command [
829			"\"%s\"",
830			foreground._flag,
831			"-colorize",
832			print val.value,
833			"\"%s\""
834		];
835
836		_result = Magick.system command x;
837	}
838}
839
840Magick_colors_item = class
841	Menuaction "_Colors" "reduce number of colors" {
842	action x = class
843		_result {
844		_vislevel = 3;
845
846		treedepth = Expression "Treedepth" 8;
847		dither = Magick.dither_widget;
848		quantize = Magick.colorspace_widget;
849		colors = Expression "Colours" 3;
850
851		command = Magick.command [
852			"\"%s\"",
853			"-quantize", quantize._flag,
854			"-treedepth",
855			print treedepth.expr,
856			dither._flag,
857			"-colors",
858			print colors.expr,
859			"\"%s\""
860		];
861
862		_result = Magick.system command x;
863	}
864}
865
866// FIXME: color-matrix?
867
868Magick_colorspace_item = class
869	Menuaction "_Colourspace" "convert to arbitrary colourspace" {
870	action x = class
871		_result {
872		_vislevel = 3;
873
874		colsp = Magick.colorspace_widget;
875
876		command = Magick.command [
877			"\"%s\"",
878			"-colorspace",
879			colsp._flag,
880			"\"%s\""
881		];
882
883		_result = Magick.system command x;
884	}
885}
886
887Magick_colorspaceGray_item = class
888	Menuaction "_Colourspace gray" "convert to gray using given intensity method" {
889	action x = class
890		_result {
891		_vislevel = 3;
892
893		intensity = Magick.intensity_widget;
894
895		command = Magick.command [
896			"\"%s\"",
897			intensity._flag,
898			"-colorspace gray",
899			"\"%s\""
900		];
901
902		_result = Magick.system command x;
903	}
904}
905
906Magick_contrast_item = class
907	Menuaction "_Contrast" "increase or reduce the contrast" {
908	action x = class
909		_result {
910		_vislevel = 3;
911
912		isReduce = Toggle "reduce contrast" false;
913
914		command = Magick.command [
915			"\"%s\"",
916			(if isReduce then "+" else "-") ++ "contrast",
917			"\"%s\""
918		];
919
920		_result = Magick.system command x;
921	}
922}
923
924Magick_contrastStretch_item = class
925	Menuaction "_Contrast stretch" "stretches tones, making some black/white" {
926	action x = class
927		_result {
928		_vislevel = 3;
929
930		intensity = Magick.intensity_widget;
931		channels = Magick.channels_widget;
932		blk = Scale "percent to make black" 0 100 0;
933		wht = Scale "percent to make white" 0 100 0;
934
935		command = Magick.command [
936			"\"%s\"",
937			intensity._flag,
938			channels._flag,
939			"-contrast-stretch",
940			"\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"",
941			"\"%s\""
942		];
943
944		_result = Magick.system command x;
945	}
946}
947
948// FIXME: convolve (bias, kernel)
949
950Magick_crop_item = class
951	Menuaction "_Crop" "cut out a rectangular region" {
952	action x = class
953		_result {
954		_vislevel = 3;
955
956		gravity = Magick.gravity_widget;
957		geometry = Magick.WhxyGeometry_widget;
958
959		command = Magick.command [
960			"\"%s\"",
961			gravity._flag,
962			"-crop",
963			geometry._flag,
964			"+repage",
965			"\"%s\""
966		];
967
968		_result = Magick.system command x;
969	}
970}
971
972Magick_deskew_item = class
973	Menuaction "_Deskew" "straighten the image" {
974	action x = class
975		_result {
976		_vislevel = 3;
977
978		threshold = Scale "Threshold (percent)" 0 100 80;
979
980		// FIXME: toggle auto-crop?
981
982		command = Magick.command [
983			"\"%s\"",
984			"-deskew",
985			"\"" ++ print threshold.value ++ "%%\"",
986			"+repage",
987			"\"%s\""
988		];
989
990		_result = Magick.system command x;
991	}
992}
993
994Magick_despeckle_item = class
995	Menuaction "_Despeckle" "reduce the speckles" {
996	action x = class
997		_result {
998		_vislevel = 3;
999
1000		command = Magick.command [
1001			"\"%s\"",
1002			"-despeckle",
1003			"\"%s\""
1004		];
1005
1006		_result = Magick.system command x;
1007	}
1008}
1009
1010Magick_distort_item = class
1011	Menuaction "_Distort" "distort using a method and arguments" {
1012	action x = class
1013		_result {
1014		_vislevel = 3;
1015
1016		virtpixback = Magick.VirtualPixelBack_widget;
1017		distort = Magick.distort_widget;
1018		args = String "Arguments" "1,0";
1019		isPlus = Toggle "Extend to show entire image" false;
1020
1021		command = Magick.command [
1022			"\"%s\"",
1023			virtpixback._flag,
1024			(if isPlus then "+" else "-") ++ "distort",
1025			distort._flag,
1026			args.value,
1027			"+repage",
1028			"\"%s\""
1029		];
1030
1031		_result = Magick.system command x;
1032	}
1033}
1034
1035Magick_draw_item = class
1036	Menuaction "_Draw" "annotate with one or more graphic primitives" {
1037	action x = class
1038		_result {
1039		_vislevel = 3;
1040
1041		foreground = Magick.foreground_widget;
1042		args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20";
1043
1044		command = Magick.command [
1045			"\"%s\"",
1046			foreground._flag,
1047			"-draw",
1048			concat ["\"", args.value, "\""],
1049			"\"%s\""
1050		];
1051
1052		_result = Magick.system command x;
1053	}
1054}
1055
1056Magick_edge_item = class
1057	Menuaction "_Edge" "detect edges" {
1058	action x = class
1059		_result {
1060		_vislevel = 3;
1061
1062		rad = Expression "Radius" 3;
1063
1064		command = Magick.command [
1065			"\"%s\"",
1066			"-edge",
1067			print rad.expr,
1068			"\"%s\""
1069		];
1070
1071		_result = Magick.system command x;
1072	}
1073}
1074
1075Magick_emboss_item = class
1076	Menuaction "_Emboss" "emboss" {
1077	action x = class
1078		_result {
1079		_vislevel = 3;
1080
1081		rad = Expression "Radius" 3;
1082
1083		command = Magick.command [
1084			"\"%s\"",
1085			"-emboss",
1086			print rad.expr,
1087			"\"%s\""
1088		];
1089
1090		_result = Magick.system command x;
1091	}
1092}
1093
1094Magick_enhance_item = class
1095	Menuaction "_Enhance" "enhance a noisy image" {
1096	action x = class
1097		_result {
1098		_vislevel = 3;
1099
1100		command = Magick.command [
1101			"\"%s\"",
1102			"-enhance",
1103			"\"%s\""
1104		];
1105
1106		_result = Magick.system command x;
1107	}
1108}
1109
1110Magick_equalize_item = class
1111	Menuaction "_Equalize" "equalize the histogram" {
1112	action x = class
1113		_result {
1114		_vislevel = 3;
1115
1116		channels = Magick.channels_widget;
1117
1118		command = Magick.command [
1119			"\"%s\"",
1120			channels._flag,
1121			"-equalize",
1122			"\"%s\""
1123		];
1124
1125		_result = Magick.system command x;
1126	}
1127}
1128
1129Magick_evaluate_item = class
1130	Menuaction "_Evaluate" "evaluate an expression on each pixel channel" {
1131	action x = class
1132		_result {
1133		_vislevel = 3;
1134
1135		channels = Magick.channels_widget;
1136		operation = Magick.evaluate_widget;
1137		val = Expression "value" 5;
1138		isPc = Toggle "Value is percent" false;
1139
1140		command = Magick.command [
1141			"\"%s\"",
1142			channels._flag,
1143			operation._flag,
1144			print val.expr ++ if isPc then "%%" else "",
1145			"\"%s\""
1146		];
1147
1148		_result = Magick.system command x;
1149	}
1150}
1151
1152Magick_extent_item = class
1153	Menuaction "_Extent" "set the image size and offset" {
1154	action x = class
1155		_result {
1156		_vislevel = 3;
1157
1158		background = Magick.background_widget;
1159		compose = Magick.compose_widget;
1160		gravity = Magick.gravity_widget;
1161		geometry = Magick.WhxyGeometry_widget;
1162
1163		command = Magick.command [
1164			"\"%s\"",
1165			compose._flag,
1166			background._flag,
1167			gravity._flag,
1168			"-extent",
1169			geometry._flag,
1170			"\"%s\""
1171		];
1172
1173		_result = Magick.system command x;
1174	}
1175}
1176
1177
1178Magick_FlipFlopMenu_item = class
1179	Menupullright "_Flip/flop" "flip/flop/transverse/transpose" {
1180
1181	Magick_flip_item = class
1182		Menuaction "_Flip vertically" "mirror upside-down" {
1183		action x = class
1184			_result {
1185			_vislevel = 3;
1186
1187			command = Magick.command [
1188				"\"%s\"",
1189				"-flip",
1190				"\"%s\""
1191			];
1192
1193			_result = Magick.system command x;
1194		}
1195	}
1196
1197	Magick_flop_item = class
1198		Menuaction "_Flop horizontally" "mirror left-right" {
1199		action x = class
1200			_result {
1201			_vislevel = 3;
1202
1203			command = Magick.command [
1204				"\"%s\"",
1205				"-flop",
1206				"\"%s\""
1207			];
1208
1209			_result = Magick.system command x;
1210		}
1211	}
1212
1213	Magick_transpose_item = class
1214		Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" {
1215		action x = class
1216			_result {
1217			_vislevel = 3;
1218
1219			command = Magick.command [
1220				"\"%s\"",
1221				"-transpose +repage",
1222				"\"%s\""
1223			];
1224
1225			_result = Magick.system command x;
1226		}
1227	}
1228
1229	Magick_transverse_item = class
1230		Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" {
1231		action x = class
1232			_result {
1233			_vislevel = 3;
1234
1235			command = Magick.command [
1236				"\"%s\"",
1237				"-transverse +repage",
1238				"\"%s\""
1239			];
1240
1241			_result = Magick.system command x;
1242		}
1243	}
1244
1245} // end Magick_FlipFlopMenu_item
1246
1247
1248Magick_floodfill_item = class
1249	Menuaction "_Floodfill" "recolour neighbours that match" {
1250	action x = class
1251		_result {
1252		_vislevel = 3;
1253
1254		foreground = Magick.foreground_widget;
1255		fuzz = Magick.fuzz_widget;
1256		coordinate = Magick.coordinate_widget;
1257
1258		// -draw "color x,y floodfill"
1259		command = Magick.command [
1260			"\"%s\"",
1261			foreground._flag,
1262			"-fuzz",
1263			"\"" ++ print fuzz.value ++ "%%\"",
1264			"-draw \" color",
1265			coordinate._flag,
1266			"floodfill \"",
1267			"\"%s\""
1268		];
1269
1270		_result = Magick.system command x;
1271	}
1272}
1273
1274Magick_frame_item = class
1275	Menuaction "_Frame" "surround with border or beveled frame" {
1276	action x = class
1277		_result {
1278		_vislevel = 3;
1279
1280		border = Magick.bordercol_widget;
1281		compose = Magick.compose_widget;
1282		matte = Magick.mattecol_widget;
1283		geometry = Magick.FrameGeometry_widget;
1284
1285		command = Magick.command [
1286			"\"%s\"",
1287			compose._flag,
1288			border._flag,
1289			matte._flag,
1290			"-frame",
1291			geometry._flag,
1292			"\"%s\""
1293		];
1294
1295		_result = Magick.system command x;
1296	}
1297}
1298
1299Magick_function_item = class
1300	Menuaction "_Function" "evaluate a function on each pixel channel" {
1301	action x = class
1302		_result {
1303		_vislevel = 3;
1304
1305		channels = Magick.channels_widget;
1306		function = Magick.function_widget;
1307		// FIXME: explain values; use sensible defaults.
1308		values = String "values" "0,0,0,0";
1309
1310		command = Magick.command [
1311			"\"%s\"",
1312			channels._flag,
1313			"-function",
1314			function._flag,
1315			values.value,
1316			"\"%s\""
1317		];
1318
1319		_result = Magick.system command x;
1320	}
1321}
1322
1323Magick_fx_item = class
1324	Menuaction "_Fx" "apply a mathematical expression" {
1325	action x = class
1326		_result {
1327		_vislevel = 3;
1328
1329		channels = Magick.channels_widget;
1330		interpolate = Magick.interpolate_widget;
1331		virtpixback = Magick.VirtualPixelBack_widget;
1332		args = String "Expression" "u*1/2";
1333
1334		command = Magick.command [
1335			"\"%s\"",
1336			channels._flag,
1337			interpolate._flag,
1338			virtpixback._flag,
1339			"-fx",
1340			concat ["\"", args.value, "\""],
1341			"\"%s\""
1342		];
1343
1344		_result = Magick.system command x;
1345	}
1346}
1347
1348Magick_gamma_item = class
1349	Menuaction "_Gamma" "apply a gamma correction" {
1350	action x = class
1351		_result {
1352		_vislevel = 3;
1353
1354		channels = Magick.channels_widget;
1355		gamma = Magick.gamma_widget;
1356
1357		command = Magick.command [
1358			"\"%s\"",
1359			channels._flag,
1360			"-gamma",
1361			print gamma.value,
1362			"\"%s\""
1363		];
1364
1365		_result = Magick.system command x;
1366	}
1367}
1368
1369Magick_gradient_item = class
1370	Menuaction "_Gradient" "apply a linear gradient" {
1371	action x = class
1372		_result {
1373		_vislevel = 3;
1374
1375		colourA = Magick.generalcol_widget;
1376		colourB = Magick.generalcol_widget;
1377
1378		position = Option "colourA is at" [
1379				"top", "bottom",
1380				"left", "right",
1381				"top-left", "top-right",
1382				"bottom-left", "bottom-right"] 0;
1383		_baryArg
1384			= concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0
1385			= concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1
1386			= concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2
1387			= concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3
1388			= concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4
1389			= concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5
1390			= concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6
1391			= concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7
1392			= "dunno";
1393
1394		command = Magick.command [
1395			"\"%s\"",
1396			"-sparse-color barycentric \"" ++ _baryArg ++ "\"",
1397			"\"%s\""
1398		];
1399
1400		_result = Magick.system command x;
1401	}
1402}
1403
1404Magick_gradientCorn_item = class
1405	Menuaction "_Gradient corners"
1406		"apply a bilinear gradient between the corners" {
1407	action x = class
1408		_result {
1409		_vislevel = 3;
1410
1411		colour_top_left = Magick.generalcol_widget;
1412		colour_top_right = Magick.generalcol_widget;
1413		colour_bottom_left = Magick.generalcol_widget;
1414		colour_bottom_right = Magick.generalcol_widget;
1415
1416		command = Magick.command [
1417			"\"%s\"",
1418			"-sparse-color bilinear \"" ++
1419				"0,0," ++ colour_top_left._flag ++
1420				",%%[fx:w-1],0" ++ colour_top_right._flag ++
1421				",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++
1422				",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"",
1423			"+depth",
1424			"\"%s\""
1425		];
1426
1427		_result = Magick.system command x;
1428	}
1429}
1430
1431Magick_histogram_item = class
1432	Menuaction "_Histogram" "make a histogram image" {
1433	action x = class
1434		_result {
1435		_vislevel = 3;
1436
1437		command = Magick.command [
1438			"\"%s\"",
1439			"-define histogram:unique-colors=false histogram:" ++
1440				"\"%s\""
1441		];
1442
1443		_result = Magick.system command x;
1444	}
1445}
1446
1447Magick_implode_item = class
1448	Menuaction "_Implode" "implode pixels about the center" {
1449	action x = class
1450		_result {
1451		_vislevel = 3;
1452
1453		factor = Scale "factor" 0 20 1;
1454		interpolate = Magick.interpolate_widget;
1455		// FIXME: virtual-pixel?
1456
1457		command = Magick.command [
1458			"\"%s\"",
1459			interpolate._flag,
1460			"-implode",
1461			print factor.value,
1462			"\"%s\""
1463		];
1464
1465		_result = Magick.system command x;
1466	}
1467}
1468
1469Magick_level_item = class
1470	Menuaction "_Level" "adjust the level of channels" {
1471	action x = class
1472		_result {
1473		_vislevel = 3;
1474
1475		channels = Magick.channels_widget;
1476		blk = Scale "black point" (-100) 200 0;
1477		wht = Scale "white point" (-100) 200 100;
1478		gam = Scale "gamma" 0 30 1;
1479		isPc = Toggle "Levels are percent" true;
1480		isInv = Toggle "Invert effect" false;
1481
1482		command = Magick.command [
1483			"\"%s\"",
1484			channels._flag,
1485			(if isInv then "+" else "-") ++ "level",
1486			"\"" ++ print blk.value ++ "," ++
1487				print wht.value ++ (if isPc then "%%" else "") ++ "," ++
1488				print gam.value ++ "\"",
1489			"\"%s\""
1490		];
1491
1492		_result = Magick.system command x;
1493	}
1494}
1495
1496Magick_levelCols_item = class
1497	Menuaction "_Level colors" "adjust levels to given colours" {
1498	action x = class
1499		_result {
1500		_vislevel = 3;
1501
1502		channels = Magick.channels_widget;
1503		colour_black = Magick.generalcol_widget;
1504		colour_white = Magick.generalcol_widget;
1505		isInv = Toggle "Invert effect" false;
1506
1507		command = Magick.command [
1508			"\"%s\"",
1509			channels._flag,
1510			(if isInv then "+" else "-") ++ "level-colors",
1511			"\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"",
1512			"\"%s\""
1513		];
1514
1515		_result = Magick.system command x;
1516	}
1517}
1518
1519Magick_linearStretch_item = class
1520	Menuaction "_Linear stretch" "stretches tones, making some black/white" {
1521	action x = class
1522		_result {
1523		_vislevel = 3;
1524
1525		channels = Magick.channels_widget;
1526		blk = Scale "percent to make black" 0 100 0;
1527		wht = Scale "percent to make white" 0 100 0;
1528
1529		command = Magick.command [
1530			"\"%s\"",
1531			channels._flag,
1532			"-linear-stretch",
1533			"\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"",
1534			"\"%s\""
1535		];
1536
1537		_result = Magick.system command x;
1538	}
1539}
1540
1541Magick_magnify_item = class
1542	Menuaction "_Magnify" "double the size of the image with pixel art scaling" {
1543	action x = class
1544		_result {
1545		_vislevel = 3;
1546
1547		command = Magick.command [
1548			"\"%s\"",
1549			"-magnify",
1550			"\"%s\""
1551		];
1552
1553		_result = Magick.system command x;
1554	}
1555}
1556
1557Magick_modulate_item = class
1558	Menuaction "_Modulate" "modulate brightness, saturation and hue" {
1559	action x = class
1560		_result {
1561		_vislevel = 3;
1562
1563		modcolsp = Magick.ModColSp_widget;
1564		bright = Scale "brightness" 0 200 100;
1565		sat = Scale "saturation" 0 200 100;
1566		hue = Scale "hue" 0 200 100;
1567
1568		command = Magick.command [
1569			"\"%s\"",
1570			modcolsp._flag,
1571			"-modulate",
1572			print bright.value ++ "," ++ print sat.value ++ "," ++
1573				print hue.value,
1574			"\"%s\""
1575		];
1576
1577		_result = Magick.system command x;
1578	}
1579}
1580
1581Magick_monochrome_item = class
1582	Menuaction "_Monochrome" "transform to black and white" {
1583	action x = class
1584		_result {
1585		_vislevel = 3;
1586
1587		// FIXME: also intensity?
1588
1589		intensity = Magick.intensity_widget;
1590		treedepth = Expression "Treedepth" 8;
1591		dither = Magick.dither_widget;
1592
1593		command = Magick.command [
1594			"\"%s\"",
1595			intensity._flag,
1596			dither._flag,
1597			"-treedepth",
1598			print treedepth.expr,
1599			"-monochrome",
1600			"\"%s\""
1601		];
1602
1603		_result = Magick.system command x;
1604	}
1605}
1606
1607Magick_morphology_item = class
1608	// See http://www.imagemagick.org/Usage/morphology/
1609	Menuaction "_Morphology" "apply a morphological method" {
1610	action x = class
1611		_result {
1612		_vislevel = 3;
1613
1614		method = Magick.morphmeth_widget;
1615		iter = Expression "Iterations (-1=repeat until done)" 1;
1616
1617		kernel = Magick.kernel_widget;
1618		// FIXME: custom kernel eg "3x1+2+0:1,0,0"
1619		//   width x height + offsx + offsy : {w*h values}
1620		//   each value is 0.0 to 1.0 or "NaN" or "-"
1621
1622		// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0
1623		// but
1624		//   ring takes: radius1, radius2, scale
1625		//   rectangle and comet take: width x height + offsx + offsy
1626		//   blur takes: radius x sigma
1627		// FIXME: for now, simply allow any string input.
1628		kernel_arg = String "Kernel arguments" "";
1629		channels = Magick.channels_widget;
1630
1631		command = Magick.command [
1632			"\"%s\"",
1633			channels._flag,
1634			"-morphology",
1635			method._flag ++ ":" ++ print iter.expr,
1636			kernel._flag ++
1637			(if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value,
1638			"\"%s\""
1639		];
1640
1641		_result = Magick.system command x;
1642	}
1643}
1644
1645Magick_negate_item = class
1646	Menuaction "_Negate" "negate" {
1647	action x = class
1648		_result {
1649		_vislevel = 3;
1650
1651		channels = Magick.channels_widget;
1652
1653		command = Magick.command [
1654			"\"%s\"",
1655			channels._flag,
1656			"-negate",
1657			"\"%s\""
1658		];
1659
1660		_result = Magick.system command x;
1661	}
1662}
1663
1664Magick_addNoise_item = class
1665	Menuaction "_add Noise" "add noise" {
1666	action x = class
1667		_result {
1668		_vislevel = 3;
1669
1670		channels = Magick.channels_widget;
1671		attenuate = Scale "attenuate" 0 1.0 1.0;
1672		noise = Magick.noise_widget;
1673
1674		command = Magick.command [
1675			"\"%s\"",
1676			channels._flag,
1677			"-attenuate",
1678			print attenuate.value,
1679			noise._flag,
1680			"\"%s\""
1681		];
1682
1683		_result = Magick.system command x;
1684	}
1685}
1686
1687Magick_normalize_item = class
1688	Menuaction "_Normalize" "normalize" {
1689	action x = class
1690		_result {
1691		_vislevel = 3;
1692
1693		intensity = Magick.intensity_widget;
1694		channels = Magick.channels_widget;
1695
1696		command = Magick.command [
1697			"\"%s\"",
1698			intensity._flag,
1699			channels._flag,
1700			"-normalize",
1701			"\"%s\""
1702		];
1703
1704		_result = Magick.system command x;
1705	}
1706}
1707
1708Magick_opaque_item = class
1709	Menuaction "_Opaque" "change this colour to the fill colour" {
1710	action x = class
1711		_result {
1712		_vislevel = 3;
1713
1714		channels = Magick.channels_widget;
1715		fill = Magick.foreground_widget;
1716		changeColour = Magick.changeCol_widget;
1717
1718		command = Magick.command [
1719			"\"%s\"",
1720			fill._flag,
1721			channels._flag,
1722			"-fuzz",
1723			"\"" ++ print changeColour.fuzz.value ++ "%%\"",
1724			(if changeColour.nonMatch then "+" else "-") ++ "opaque",
1725			"\"" ++ changeColour.colour._flag ++ "\"",
1726			"\"%s\""
1727		];
1728
1729		_result = Magick.system command x;
1730	}
1731}
1732
1733Magick_paint_item = class
1734	Menuaction "_Paint" "simulate an oil painting" {
1735	action x = class
1736		_result {
1737		_vislevel = 3;
1738
1739		rad = Expression "radius" 10;
1740
1741		command = Magick.command [
1742			"\"%s\"",
1743			"-paint",
1744			print rad.expr,
1745			"\"%s\""
1746		];
1747
1748		_result = Magick.system command x;
1749	}
1750}
1751
1752/*=== FIXME Bug; remove for now.
1753Polaroid_item = class
1754	Menuaction "_Polaroid" "simulate a polaroid picture" {
1755	action x = class
1756		_result {
1757		_vislevel = 3;
1758
1759		angle = Scale "angle" (-90) 90 20;
1760
1761		command = Magick.command [
1762			"\"%s\"",
1763			"-polaroid",
1764			print angle.value,
1765			"\"%s\""
1766		];
1767
1768		_result = Magick.system command x;
1769	}
1770}
1771===*/
1772
1773Magick_posterize_item = class
1774	Menuaction "_Posterize" "reduce to (n) levels per channel" {
1775	action x = class
1776		_result {
1777		_vislevel = 3;
1778
1779		levels = Expression "levels" 3;
1780
1781		command = Magick.command [
1782			"\"%s\"",
1783			"-posterize",
1784			print levels.expr,
1785			"\"%s\""
1786		];
1787
1788		_result = Magick.system command x;
1789	}
1790}
1791
1792Magick_raise_item = class
1793	Menuaction "_Raise" "lighten or darken image edges" {
1794	action x = class
1795		_result {
1796		_vislevel = 3;
1797
1798		thk = Expression "Thickness" 3;
1799
1800		command = Magick.command [
1801			"\"%s\"",
1802			"-raise",
1803			print thk.expr,
1804			"\"%s\""
1805		];
1806
1807		_result = Magick.system command x;
1808	}
1809}
1810
1811Magick_resize_item = class
1812	Menuaction "_Resize" "resize to given width and height" {
1813	action x = class
1814		_result {
1815		_vislevel = 3;
1816
1817		filter = Magick.filter_widget;
1818		type = Magick.ResizeType_widget;
1819		width = Scale "Width" 1 100 10;
1820		height = Scale "Height" 1 100 10;
1821		isPc = Toggle "Width and height are percent" false;
1822
1823		command = Magick.command [
1824			"\"%s\"",
1825			filter._flag,
1826			"-" ++ type._flag,
1827			"\"" ++ print width.value ++ "x" ++ print height.value ++
1828				(if isPc then "%%" else "!") ++ "\"",
1829			"\"%s\""
1830		];
1831
1832		_result = Magick.system command x;
1833	}
1834}
1835
1836Magick_roll_item = class
1837	Menuaction "_Roll" "roll an image horizontally or vertically" {
1838	action x = class
1839		_result {
1840		_vislevel = 3;
1841
1842		rollx = Expression "X" 3;
1843		rolly = Expression "Y" 3;
1844
1845		command = Magick.command [
1846			"\"%s\"",
1847			"-roll",
1848			(if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++
1849			(if rolly.expr >= 0 then "+" else "") ++ print rolly.expr,
1850			"\"%s\""
1851		];
1852
1853		_result = Magick.system command x;
1854	}
1855}
1856
1857Magick_rotate_item = class
1858	Menuaction "_Rotate" "rotate" {
1859	action x = class
1860		_result {
1861		_vislevel = 3;
1862
1863		angle = Scale "angle (degrees)" (-360) 360 20;
1864		virtpixback = Magick.VirtualPixelBack_widget;
1865
1866		command = Magick.command [
1867			"\"%s\"",
1868			virtpixback._flag,
1869			"+distort",
1870			"SRT",
1871			print angle.value,
1872			"+repage",
1873			"\"%s\""
1874		];
1875
1876		_result = Magick.system command x;
1877	}
1878}
1879
1880// FIXME: -segment, but cluster-threshold should be percentage of image area.
1881
1882Magick_sepia_item = class
1883	Menuaction "_Sepia tone" "simulate a sepia-toned photo" {
1884	action x = class
1885		_result {
1886		_vislevel = 3;
1887
1888		threshold = Scale "Threshold (percent)" 0 100 80;
1889
1890		command = Magick.command [
1891			"\"%s\"",
1892			"-sepia-tone",
1893			"\"" ++ print threshold.value ++ "%%\"",
1894			"\"%s\""
1895		];
1896
1897		_result = Magick.system command x;
1898	}
1899}
1900
1901Magick_shade_item = class
1902	Menuaction "_Shade" "shade with a distant light source" {
1903	action x = class
1904		_result {
1905		_vislevel = 3;
1906
1907		azimuth = Scale "Azimuth (degrees)" (-360) 360 0;
1908		elevation = Scale "Elevation (degrees)" 0 90 45;
1909
1910		command = Magick.command [
1911			"\"%s\"",
1912			"-shade",
1913			print azimuth.value ++ "x" ++ print elevation.value,
1914			"\"%s\""
1915		];
1916
1917		_result = Magick.system command x;
1918	}
1919}
1920
1921Magick_shadow_item = class
1922	Menuaction "_Shadow" "simulate a shadow" {
1923	action x = class
1924		_result {
1925		_vislevel = 3;
1926
1927		shadowCol = Magick.generalcol_widget;
1928		opacity = Scale "Opacity (percent)" 0 100 75;
1929		sigma = Scale "Sigma" 0 30 2;
1930		// FIXME: make offsets a single widget?
1931		offsx = Scale "X-offset" (-20) 20 4;
1932		offsy = Scale "Y-offset" (-20) 20 4;
1933		arePc = Toggle "offsets are percentages" false;
1934
1935		// FIXME: raw operation creates page offset, which vips dislikes.
1936		// So we take this futher, compositing with source.
1937		command = Magick.command [
1938			"\"%s\"",
1939			"\"(\" +clone",
1940			"-background", "\"" ++ shadowCol._flag ++ "\"",
1941			"-shadow",
1942			concat [
1943				"\"",
1944				print opacity.value, "x", print sigma.value,
1945				(if offsx.value >= 0 then "+" else ""), print offsx.value,
1946				(if offsy.value >= 0 then "+" else ""), print offsy.value,
1947				(if arePc then "%%" else ""),
1948				"\""
1949			],
1950			"\")\" +swap -background None -layers merge",
1951			"+repage",
1952			"\"%s\""
1953		];
1954
1955		_result = Magick.system command x;
1956	}
1957}
1958
1959Magick_shave_item = class
1960	Menuaction "_Shave" "shave pixels from the edges" {
1961	action x = class
1962		_result {
1963		_vislevel = 3;
1964
1965		width = Scale "Width" 0 50 10;
1966		height = Scale "Height" 0 50 10;
1967		isPc = Toggle "Width and height are percent" false;
1968
1969		command = Magick.command [
1970			"\"%s\"",
1971			"-shave",
1972			"\"" ++ print width.value ++ "x" ++ print height.value ++
1973				(if isPc then "%%" else "") ++ "\"",
1974			"\"%s\""
1975		];
1976
1977		_result = Magick.system command x;
1978	}
1979}
1980
1981Magick_shear_item = class
1982	Menuaction "_Shear" "shear along the x-axis and/or y-axis" {
1983	action x = class
1984		_result {
1985		_vislevel = 3;
1986
1987		shearX = Expression "shear X (degrees)" 0;
1988		shearY = Expression "shear Y (degrees)" 0;
1989		background = Magick.background_widget;
1990
1991		command = Magick.command [
1992			"\"%s\"",
1993			background._flag,
1994			"-shear",
1995			print shearX.expr ++ "x" ++ print shearY.expr,
1996			"\"%s\""
1997		];
1998
1999		_result = Magick.system command x;
2000	}
2001}
2002
2003Magick_sigmoid_item = class
2004	Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" {
2005	action x = class
2006		_result {
2007		_vislevel = 3;
2008
2009		channels = Magick.channels_widget;
2010		contrast = Scale "contrast" 0 30 3;
2011		midpoint = Scale "mid-point (percent)" 0 100 50;
2012		isInv = Toggle "Invert effect" false;
2013
2014		command = Magick.command [
2015			"\"%s\"",
2016			channels._flag,
2017			(if isInv then "+" else "-") ++ "sigmoidal-contrast",
2018			"\"" ++ print contrast.value ++ "x" ++
2019				print midpoint.value ++ "%%\"",
2020			"\"%s\""
2021		];
2022
2023		_result = Magick.system command x;
2024	}
2025}
2026
2027Magick_sketch_item = class
2028	Menuaction "_Sketch" "simulate a pencil sketch" {
2029	action x = class
2030		_result {
2031		_vislevel = 3;
2032
2033		radius = Magick.blur_rad_widget;
2034		sigma = Magick.sigma_widget;
2035		angle = Scale "angle" (-360) 360 0;
2036
2037		command = Magick.command [
2038			"\"%s\"",
2039			"-sketch",
2040			print radius.value ++ "x" ++ print sigma.value ++
2041				(if angle >= 0 then ("+" ++ print angle.value) else ""),
2042			"\"%s\""
2043		];
2044
2045		_result = Magick.system command x;
2046	}
2047}
2048
2049Magick_solarize_item = class
2050	Menuaction "_Solarize" "negate all pixels above a threshold level" {
2051	action x = class
2052		_result {
2053		_vislevel = 3;
2054
2055		channels = Magick.channels_widget;
2056		threshold = Scale "Threshold (percent)" 0 100 50;
2057
2058		command = Magick.command [
2059			"\"%s\"",
2060			channels._flag,
2061			"-solarize",
2062			"\"" ++ print threshold.value ++ "%%\"",
2063			"\"%s\""
2064		];
2065
2066		_result = Magick.system command x;
2067	}
2068}
2069
2070// FIXME: -sparse-color needs abitrary list of {x,y,colour}.
2071
2072Magick_splice_item = class
2073	Menuaction "_Splice" "splice a colour into the image" {
2074	action x = class
2075		_result {
2076		_vislevel = 3;
2077
2078		background = Magick.background_widget;
2079		gravity = Magick.gravity_widget;
2080		geometry = Magick.WhxyGeometry_widget;
2081
2082		command = Magick.command [
2083			"\"%s\"",
2084			background._flag,
2085			gravity._flag,
2086			"-splice",
2087			geometry._flag,
2088			"\"%s\""
2089		];
2090
2091		_result = Magick.system command x;
2092	}
2093}
2094
2095Magick_spread_item = class
2096	Menuaction "_Spread" "displace pixels by random amount" {
2097	action x = class
2098		_result {
2099		_vislevel = 3;
2100
2101		virtpixback = Magick.VirtualPixelBack_widget;
2102		amount = Expression "Amount (pixels)" 5;
2103
2104		command = Magick.command [
2105			"\"%s\"",
2106			virtpixback._flag,
2107			"-spread",
2108			print amount.expr,
2109			"\"%s\""
2110		];
2111
2112		_result = Magick.system command x;
2113	}
2114}
2115
2116Magick_statistic_item = class
2117	Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" {
2118	action x = class
2119		_result {
2120		_vislevel = 3;
2121
2122		width = Expression "Width" 5;
2123		height = Expression "Height" 5;
2124		statisticType = Magick.StatType_widget;
2125
2126		command = Magick.command [
2127			"\"%s\"",
2128			"-statistic",
2129			statisticType._flag,
2130			print width.expr ++ "x" ++ print height.expr,
2131			"\"%s\""
2132		];
2133
2134		_result = Magick.system command x;
2135	}
2136}
2137
2138Magick_swirl_item = class
2139	Menuaction "_Swirl" "swirl around the centre" {
2140	action x = class
2141		_result {
2142		_vislevel = 3;
2143
2144		angle = Magick.angle_widget;
2145
2146		command = Magick.command [
2147			"\"%s\"",
2148			"-swirl",
2149			print angle.value,
2150			"\"%s\""
2151		];
2152
2153		_result = Magick.system command x;
2154	}
2155}
2156
2157Magick_thresholdMenu_item = class
2158	Menupullright "_Threshold" "make black or white" {
2159
2160	Magick_threshold_item = class
2161		Menuaction "_Threshold" "apply black/white threshold" {
2162		action x = class
2163			_result {
2164			_vislevel = 3;
2165
2166			intensity = Magick.intensity_widget;
2167			channels = Magick.channels_widget;
2168			threshold = Scale "Threshold (percent)" 0 100 50;
2169
2170			command = Magick.command [
2171				"\"%s\"",
2172				intensity._flag,
2173				channels._flag,
2174				"-threshold",
2175				"\"" ++ print threshold.value ++ "%%\"",
2176				"\"%s\""
2177			];
2178
2179			_result = Magick.system command x;
2180		}
2181	}
2182
2183	Magick_blackThreshold_item = class
2184		Menuaction "_Black threshold" "where below threshold set to black" {
2185		action x = class
2186			_result {
2187			_vislevel = 3;
2188
2189			channels = Magick.channels_widget;
2190			threshold = Scale "Threshold (percent)" 0 100 50;
2191
2192			command = Magick.command [
2193				"\"%s\"",
2194				channels._flag,
2195				"-black-threshold",
2196				"\"" ++ print threshold.value ++ "%%\"",
2197				"\"%s\""
2198			];
2199
2200			_result = Magick.system command x;
2201		}
2202	}
2203
2204	Magick_whiteThreshold_item = class
2205		Menuaction "_White threshold" "where above threshold set to white" {
2206		action x = class
2207			_result {
2208			_vislevel = 3;
2209
2210			channels = Magick.channels_widget;
2211			threshold = Scale "Threshold (percent)" 0 100 50;
2212
2213			command = Magick.command [
2214				"\"%s\"",
2215				channels._flag,
2216				"-white-threshold",
2217				"\"" ++ print threshold.value ++ "%%\"",
2218				"\"%s\""
2219			];
2220
2221			_result = Magick.system command x;
2222		}
2223	}
2224
2225	Magick_latThreshold_item = class
2226		Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" {
2227		action x = class
2228			_result {
2229			_vislevel = 3;
2230
2231			width = Expression "Width" 10;
2232			height = Expression "Height" 10;
2233			offset = Scale "Offset (percent)" (-100) 100 0;
2234			// note: "-lat" doesn't respond to channels
2235
2236			command = Magick.command [
2237				"\"%s\"",
2238				"-lat",
2239				concat ["\"", print width.expr, "x", print height.expr,
2240					(if offset.value >= 0 then "+" else ""), print offset.value,
2241					"%%\""
2242				],
2243				"\"%s\""
2244			];
2245
2246			_result = Magick.system command x;
2247		}
2248	}
2249
2250	Magick_randThreshold_item = class
2251		Menuaction "_Random Threshold" "between specified limits, apply random threshold" {
2252		action x = class
2253			_result {
2254			_vislevel = 3;
2255
2256			channels = Magick.channels_widget;
2257			low = Scale "Low threshold" 0 100 10;
2258			high = Scale "High threshold" 0 100 90;
2259			isPc = Toggle "Thresholds are percent" true;
2260
2261			command = Magick.command [
2262				"\"%s\"",
2263				channels._flag,
2264				"-random-threshold",
2265				"\"" ++ print low.value ++ "x" ++ print high.value ++
2266					(if isPc then "%%" else "") ++ "\"",
2267				"\"%s\""
2268			];
2269
2270			_result = Magick.system command x;
2271		}
2272	}
2273
2274} // end ThresholdMenu_item
2275
2276
2277// Note: alternatives include:
2278// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif
2279
2280Magick_tile_item = class
2281	Menuaction "_Tile" "fill given size with tiled image" {
2282	action x = class
2283		_result {
2284		_vislevel = 3;
2285
2286		size = Magick.Size_widget;
2287
2288		command = Magick.command [
2289			size._flag,
2290			"tile:" ++ "\"%s\"",
2291			"\"%s\""
2292		];
2293
2294		_result = Magick.system command x;
2295	}
2296}
2297
2298Magick_tint_item = class
2299	Menuaction "_Tint" "apply a tint" {
2300	action x = class
2301		_result {
2302		_vislevel = 3;
2303
2304		foreground = Magick.foreground_widget;
2305		amount = Scale "amount (percent)" 0 100 50;
2306
2307		command = Magick.command [
2308			"\"%s\"",
2309			foreground._flag,
2310			"-tint",
2311			// snibgo note: although the amount is a percentage, it doesn't need "%" character.
2312			print amount.value,
2313			"\"%s\""
2314		];
2315
2316		_result = Magick.system command x;
2317	}
2318}
2319
2320Magick_transparent_item = class
2321	Menuaction "_Transparent" "make this colour transparent" {
2322	action x = class
2323		_result {
2324		_vislevel = 3;
2325
2326		changeColour = Magick.changeCol_widget;
2327
2328		command = Magick.command [
2329			"\"%s\"",
2330			"-fuzz",
2331			"\"" ++ print changeColour.fuzz.value ++ "%%\"",
2332			(if changeColour.nonMatch then "+" else "-") ++ "transparent",
2333			"\"" ++ changeColour.colour._flag ++ "\"",
2334			"\"%s\""
2335		];
2336
2337		_result = Magick.system command x;
2338	}
2339}
2340
2341Magick_trim_item = class
2342	Menuaction "_Trim" "trims away border" {
2343	action x = class
2344		_result {
2345		_vislevel = 3;
2346
2347		fuzz = Magick.fuzz_widget;
2348
2349		command = Magick.command [
2350			"\"%s\"",
2351			"-fuzz",
2352			"\"" ++ print fuzz.value ++ "%%\"",
2353			"-trim +repage",
2354			"\"%s\""
2355		];
2356
2357		_result = Magick.system command x;
2358	}
2359}
2360
2361Magick_uniqueCols_item = class
2362	Menuaction "_Unique colours" "discard all but one of any pixel color" {
2363	action x = class
2364		_result {
2365		_vislevel = 3;
2366
2367		command = Magick.command [
2368			"\"%s\"",
2369			"-unique-colors",
2370			"\"%s\""
2371		];
2372
2373		_result = Magick.system command x;
2374	}
2375}
2376
2377Magick_vignette_item = class
2378	Menuaction "_Vignette" "soften the edges in vignette style" {
2379	action x = class
2380		_result {
2381		_vislevel = 3;
2382
2383		radius = Magick.blur_rad_widget;
2384		sigma = Magick.sigma_widget;
2385		rx = Scale "Rolloff x (percent)" 0 100 10;
2386		ry = Scale "Rolloff y (percent)" 0 100 10;
2387		background = Magick.background_widget;
2388
2389		command = Magick.command [
2390			"\"%s\"",
2391			background._flag,
2392			"-vignette",
2393			print radius.value ++ "x" ++ print sigma.value ++
2394				(if rx.value >= 0 then "+" else "") ++ print rx.value ++
2395				(if ry.value >= 0 then "+" else "") ++ print ry.value,
2396			"\"%s\""
2397		];
2398
2399		_result = Magick.system command x;
2400	}
2401}
2402
2403Magick_wave_item = class
2404	Menuaction "_Wave" "shear the columns into a sine wave" {
2405	action x = class
2406		_result {
2407		_vislevel = 3;
2408
2409		amplitude = Scale "Amplitude (pixels)" 0 100 10;
2410		wavelength = Scale "Wavelength (pixels)" 0 100 10;
2411
2412		command = Magick.command [
2413			"\"%s\"",
2414			"-wave",
2415			print amplitude.value ++ "x" ++ print wavelength.value,
2416			"\"%s\""
2417		];
2418
2419		_result = Magick.system command x;
2420	}
2421}
2422
2423
2424