/*
Global Change Links ver. 2.9
Скрипт предназначен для замены изображений документа
на файлы с аналогичными именами в выбранной папке.
∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
An InDesign CS2-CS3 JavaScript
OS: Mac OS X, Windows XP.
∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
Базовые задачи:
1) восстановление потерянных связей с файлами 
нестандартных «сборок проектов» (Package Publication) при переносе, 
включая межсистемный;
2) замещение предварительных изображений в документе 
на обработанные, при неизменных пропорциях высоты и ширины
(без «кадрирования» (Crop Image)  и изменения Canvas Size).
∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
Настройки скрипта:
1) выбор изображений документа по состоянию связи с файлом;
2) диапазон страниц замещения изображений, задается именами страниц и секциями документа
(выбор секции обладает большим приоритетом);
3) «пошаговый режим перелинковки» Step Mode:
• установка Center Content 100%, 0° – горизонтальное и вертикальное масштабирование - 100%,  
углы вращения и горизонтального сдвига -  0°, изображение по центру фрейма;
• установка Clipping Path Type: None – отключить «обтравочный путь»;
• проверка параметров прозрачности – Blending Settings (Opacity < 100%, Blending Mode - не «Normal»);
• проверка вращение изображения (±90°), при обнаружении несоответствия отношения 
вертикального и горизонтального масштабов изображений (для обработанных изображений); 
4) включая изображения с атрибутом «не печатать» – Nonprinting;
5) типы изображений для замены в заданном диапазоне страниц;
6) установки для сопоставления имен исходных и файлов выбранной папки – 
если имена файлов не совпадают («Non-identical»):
a) выбор окончания имени файла, содержащего более одного символа «точка»;
b) выбор расширения файлов в выбранной папке;
7) формирование и отображение отчета замещения файлов.

Реализовано:
• извлечение внедренных файлов изображений документа;
• проверка атрибута «не печатать»,
• поиск типов изображений документа;
• поиск расширений файлов в выбранной папке;
• Unlock Position для групп и объектов с графическими изображениями;
• сохранение настроек и пути к выбранной папке в файле инициализации
(создается при первом запуске скрипта).  

При замещении изображений: 
1)	сохраняются геометрические координаты изображений – Geometric Bounds
(если не установлено в настройках «Center Content 100%, 0°»);
2)	игнорируются: 
• файлы с дублирующимися именами с расширением - при замене на тип файлов «идентичный», 
без расширения - при замене на выбранный тип, при отличающихся полных именах файлов;
• изображения, находящиеся вне страниц документа (PB);
• изображения, помещенные из буфера обмена (отсутствует описание связи с файлом).
∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙
You use this script at your own fear and risk.
© 2008 Дмитрий Лапаев (d.lapaev@univest-prepress.com, d.lapaev@gmail.com). 
*/
with (app) 
{	
	if (documents.length == 0) 
	{alert("No Documents are Open! \nPlease Open a Document and try again."); exit();}
	
	var myDoc = activeDocument;
	try {activeDocument.filePath}
	catch (error) {alert("Please Save " + myDoc.name + " and try again."); exit();}
	
	if (myDoc.links.length == 0) 
	{alert("No Links in Document!"); exit();}
	
	const myScrVer = "2.9";
	// версия InDesign
	try{const InDver = version.substr(0,3);}
	catch(error){alert("Global Change Links " + myScrVer + "\nis not compatible with this version of InDesign!"); exit();}
	// количество страниц в документе
	var myDocPgsLength = myDoc.pages.length;
	const nameNCE = "identical";
	const IniFName = "lgcl_inix.txt";
	// максимальная величина допуска отношений горизонтального и вертикального масштабов изображений
	const myVGScDop = 0.01;
	var mn = "\u00A9\ \u0044\u006D\u0069\u0074\u0072\u0069\u0079\ \u004C\u0061\u0070\u0061\u0065\u0076";
	// создание файла инициализации 
	var MyStrIniF = "";
	var lgclIniF = new File (activeScript.path + "/" + IniFName);
	if (!lgclIniF.exists) 
		{	
			MyStrIniF += "var inpVLinkStM = 0;\n";
			MyStrIniF += "var inScriptName = \"Global Change Links " + myScrVer + "\";\n";
			MyStrIniF += "var inpDefPath = activeDocument.filePath;\n";
			MyStrIniF += "var inStepMode = true;\n";
			MyStrIniF += "var inShowReport = true;\n";
			MyStrIniF += "var inClippPathNone = false;\n";
			MyStrIniF += "var inCenterCont = false;\n";
			MyStrIniF += "var inCheckRotImage = true;\n";
			MyStrIniF += "var inpOrdDotN = true;\n";
			MyStrIniF += "var inpNotIdcl = true;\n";
			MyStrIniF += "var inpInSec = false;\n";
			MyStrIniF += "var inCheckTransp = true;\n";
			MyStrIniF += "var inNonprintIm = true;\n";
			MyStrIniF += "const mn = \"" + mn + "\";";
			lgclIniF.open("w");
			if (lgclIniF.write(MyStrIniF)== true) 
				{
					alert (IniFName + " successfully created!");
					lgclIniF.close();
					eval ("//@include \'" + IniFName + "\';");
				}
			else {alert("Unable to write the ini-file!"); exit();}
		} 
	else {eval ("//@include \'" + IniFName + "\';"); cr();}
	// выбор папки с изображениями
	var myNIdir = Folder.selectDialog(inScriptName + ". Select the Folder with Images for Relink", inpDefPath);
	if(myNIdir != null) var MyNewDir = myNIdir;  
	else {exit();}	
	// определяем расширения файлов выбранной папки, исключаем системные
	var MyFiles = new Array();
	var NewImagesExtType = new Array();
	MyFiles = MyNewDir.getFiles("*");
	if (MyFiles.length == 0) 
	{alert(inScriptName + "\nThe Folder \\" + Folder.decode(MyNewDir.name) + "\\ is empty\nor contains illegal characters in its name! (Mac OS X)"); exit();}
	// фильтр - получаем типы расширений файлов выбранной папки
	NewImagesExtType =  ExtenSysCheck(MyFiles);
	if (NewImagesExtType.length == 0)
	{alert(inScriptName + "\nСannot Find Graphic Files in Folder: \"" + Folder.decode(MyNewDir.name) + "\"!"); exit();}
	// заполняем массив типов изображений документа
	var DocSelType = new Array();
	var TypeFileMyDoc = GetFileTypeInDoc (myDoc);
	for (var objCounter = 0; objCounter < TypeFileMyDoc.length; objCounter++) 
	{DocSelType.push([true, TypeFileMyDoc[objCounter][0]]);}
	// считаем связи с файлами по состояниям
	var myLinksCounters = myDocLinksCounters(myDoc);
	var ArrStatusL = new Array(); 
	for (objCounter = 0; objCounter < 4; objCounter++) 
	ArrStatusL.push("(" + myLinksCounters[objCounter] + ") ");
	// формируем массив выбора состояний связей
	var inpVLinkStArr = new Array(["Missing", false], ["Normal", false], ["Modified", false], ["All Links", false]);
	inpVLinkStArr[inpVLinkStM][1] = true;
	// имена первой и последней страниц документа
	var DocNumberPageStart = myDoc.pages[0].name;
	var DocNumberPageEnd = myDoc.pages[myDocPgsLength-1].name;
	// массив параметров секций
	var ASecPar = SecRangeOfPages(myDoc);
	// тип файловой системы (ОС)
	var WonFS = File.fs;
	if (WonFS == "Macintosh") WonFS = "Mac OS X";
	// диалог 
	var myDialog = dialogs.add({name: inScriptName + " (InDesign " + InDver + " on " + WonFS + ") " + mn});
	var myCheckArray = new Array();
	with(myDialog.dialogColumns.add().dialogRows.add()) 
			{		
				with(borderPanels.add().dialogColumns.add())		
					{	
						staticTexts.add({staticLabel:"Relink"});
						// панель выбора изображений документа по типу состояния связи с файлом
						with(borderPanels.add().dialogColumns.add())
							{
								var myDocLinksSatus = radiobuttonGroups.add();	
								for (StC = 0; StC < inpVLinkStArr.length; StC++) 
								myDocLinksSatus.radiobuttonControls.add({staticLabel: ArrStatusL[StC] + inpVLinkStArr[StC][0], checkedState:inpVLinkStArr[StC][1], minWidth:170});
							}
						// панель выбора диапазона страниц
						with(borderPanels.add().dialogColumns.add())
							{	
								dialogRows.add().staticTexts.add({staticLabel:"Range of Pages (" + myDocPgsLength + "):"});
								with(dialogRows.add())
									{
										// задаем имена первой и последней страниц документа
										var	PageRangeStart = textEditboxes.add({editContents:DocNumberPageStart, minWidth: 82});
										var	PageRangeEnd = textEditboxes.add({editContents:DocNumberPageEnd, minWidth: 83});
									}	
							}
						// секции документа
						var SecNSelect = 0;
						var MySelNumbSection = enablingGroups.add({staticLabel:"Section (" + ASecPar.length + "):", checkedState:inpInSec});
						if (ASecPar.length > 1) 
							{	
								var SecNList = new Array();
								var nSecPx;
								var mySecRange;
								with(MySelNumbSection)
									{	
										for (objCounter = 0; objCounter < ASecPar.length ; objCounter++) 
											{
												if (ASecPar[objCounter][1]  == true) nSecPx = ASecPar[objCounter][2];
												else nSecPx = "";
												mySecRange = nSecPx + ASecPar[objCounter][3] + "-" + nSecPx + (ASecPar[objCounter][3]+ASecPar[objCounter][4]-1);
												SecNList.push((objCounter+1) + "\| " + mySecRange);
											}
										SecNSelect = dropdowns.add({stringList:SecNList, selectedIndex: 0, minWidth:176});
									}	
							}
						// варианты замены изображений
						staticTexts.add({staticLabel:"Options:", minWidth: 170});
						var MyStepByStepMode = enablingGroups.add({staticLabel:"Step Mode", checkedState:inStepMode});
						with(MyStepByStepMode.dialogColumns.add())
							{	
					
								var myCenterContent = checkboxControls.add({staticLabel: "Center Content 100%, 0°", checkedState:inCenterCont, minWidth: 170});
								var myClippPathNone = checkboxControls.add({staticLabel: "Clipping Path to None", checkedState:inClippPathNone});
								var myChTransparency = checkboxControls.add({staticLabel: "Check Transparency", checkedState:inCheckTransp});
								var myPossRotateIm = checkboxControls.add({staticLabel: "Check Rotate 90°", checkedState:inCheckRotImage});	
							}
						var myNonprintImagesRelink = checkboxControls.add({staticLabel: "Incl. Non-printing Images", checkedState:inNonprintIm});
					}
				with(borderPanels.add().dialogColumns.add()) 
					{
						// панель выбора типов файлов документа для замены
						staticTexts.add({staticLabel:"Selecting a Types for Relink"});			
						with(borderPanels.add().dialogColumns.add())
							{
								for (objCounter = 0; objCounter < TypeFileMyDoc.length; objCounter++) 
								myCheckArray[objCounter] = checkboxControls.add({staticLabel: Str_inskbk(TypeFileMyDoc[objCounter][0]) + " (" + TypeFileMyDoc[objCounter][1] + ")", checkedState:true, minWidth:170});	
							}
						staticTexts.add({staticLabel:"Filenames:", minWidth: 170});	
						var MyTypeNFname = enablingGroups.add({staticLabel:"Non-" + nameNCE, checkedState:inpNotIdcl});
						with(MyTypeNFname.dialogColumns.add())
							{	
								// панель выбора окончания имени файла (для имен связанных файлов с несколькими точками в имени)
								with(borderPanels.add().dialogColumns.add()) 
									{
										dialogRows.add().staticTexts.add({staticLabel:"End of New Filename:"});
										var myDotFLord = radiobuttonGroups.add();	
										myDotFLord.radiobuttonControls.add({staticLabel: "First Dot", checkedState: inpOrdDotN, minWidth:146});
										myDotFLord.radiobuttonControls.add({staticLabel: "Last Dot", checkedState: !inpOrdDotN});
									}
										// панель выбора расширений файлов, найденных в папке
								with(borderPanels.add().dialogColumns.add()) 
									{
										dialogRows.add().staticTexts.add({staticLabel:"New Extension:"});
										var MyTypesForChange = new Array();
										for (objCounter = 0; objCounter < NewImagesExtType.length; objCounter++) 
										MyTypesForChange.push("." + NewImagesExtType[objCounter]);
										var myNewImagesExtSelect = dropdowns.add({stringList:MyTypesForChange, selectedIndex: 0, minWidth:146});	
										dialogRows.add().staticTexts.add({staticLabel:"in a folder found: " + NewImagesExtType.length});		
									}
							}
						var myShowReportRelink = checkboxControls.add({staticLabel: "Show Report", checkedState:inShowReport});	
					}					
			}		
	// отображаем диалог
	var myResult = myDialog.show();
	if (myResult == false) {myDialog.destroy(); exit();}
	// записываем выбранные установки в файл инициализации
	var myIndexButLinksSt = myDocLinksSatus.selectedButton;
	var myButFirstDotName;
	if (myDotFLord.selectedButton == 0) myButFirstDotName = true;
	else myButFirstDotName = false;
	var mySelSectPR = MySelNumbSection.checkedState;
	var myChTransOp = myChTransparency.checkedState;
	var MyNDirAbsURI = MyNewDir.absoluteURI;
	MyStrIniF = "";
	MyStrIniF += "var inpVLinkStM = " + myIndexButLinksSt + ";\n";
	MyStrIniF += "var inScriptName = \"Global Change Links " + myScrVer + "\";\n";
	MyStrIniF += "var inpDefPath = \"" + MyNDirAbsURI.substr(0, MyNDirAbsURI.lastIndexOf("/")) + "\";\n";
	MyStrIniF += "var inStepMode = " + MyStepByStepMode.checkedState + ";\n";
	MyStrIniF += "var inShowReport = " + myShowReportRelink.checkedState + ";\n";
	MyStrIniF += "var inClippPathNone = " + myClippPathNone.checkedState + ";\n";
	MyStrIniF += "var inCenterCont = " + myCenterContent.checkedState + ";\n";
	MyStrIniF += "var inCheckRotImage = " + myPossRotateIm.checkedState + ";\n";
	MyStrIniF += "var inpOrdDotN = " + myButFirstDotName + ";\n";
	MyStrIniF += "var inpNotIdcl = " + MyTypeNFname.checkedState + ";\n";
	MyStrIniF += "var inpInSec = " + mySelSectPR + ";\n";
	MyStrIniF += "var inCheckTransp = " + myChTransOp + ";\n";
	MyStrIniF += "var inNonprintIm = " + myNonprintImagesRelink.checkedState + ";\n";
	MyStrIniF += "const mn = \"" + mn + "\";";
	lgclIniF.open("w");
	if (lgclIniF.write(MyStrIniF)== true) {lgclIniF.close();}
	else {alert("Error writing to the ini-file!");}	
	// переменные диапазона страниц для поиска изображений 
	var PRSedcont = PageRangeStart.editContents;	
	var PREedcont = PageRangeEnd.editContents;
	var mySelSecStartAbs = 0;
	var mySelSecEndsAbs = myDocPgsLength;
	if (ASecPar.length > 1 & mySelSectPR == true) 
		{
			SecNSelect = SecNSelect.selectedIndex;
			mySelSecStartAbs = ASecPar[SecNSelect][0];
			mySelSecEndsAbs = mySelSecStartAbs + ASecPar[SecNSelect][4];
		}
	// присваиваем выбранный тип для замещения
	var mySelectedExt ;
	var ResIndexSelectExt = myNewImagesExtSelect.selectedIndex ;
	if (MyTypeNFname.checkedState == false) mySelectedExt = nameNCE; 
	else mySelectedExt = NewImagesExtType[ResIndexSelectExt];
	var mySTdocStr = new Array();
	// выбранные для замещения типы документа
	for(objCounter = 0; objCounter < DocSelType.length; objCounter++) 
		{
			DocSelType[objCounter][0] = myCheckArray[objCounter].checkedState;
			if(DocSelType[objCounter][0] == true) mySTdocStr.push(Str_inskbk(DocSelType[objCounter][1]));
		}
	// формируем массив изображений документа по установленным условиям
	var MyGraphicsPages = new Array();
	// выборка всех изображений из заданного диапазона страниц
	MyGraphicsPages = RangePagesGraphics (myDoc, PRSedcont, PREedcont, mySelSectPR, mySelSecStartAbs, mySelSecEndsAbs);
	PRSedcont = MyGraphicsPages[1]
	PREedcont = MyGraphicsPages[2];
	// массив имен файлов изображений с атрибутом "не печатать" 
	var myImagesWithANonpr = new Array();
	// удаляем (при выборе в диалоге) изображения с атрибутом "не печатать" 
	MyGraphicsPages = myPrint_ObjArray(MyGraphicsPages[0], MyStepByStepMode.checkedState, myNonprintImagesRelink.checkedState, myImagesWithANonpr) 
	// выбираем по статусу состояния связи с файлом изображения
	MyGraphicsPages = selMissNormModAll_Links(MyGraphicsPages, myIndexButLinksSt);
	// выборка по обозначенным типам изображений
	MyGraphicsPages = getTypeRastrImages(MyGraphicsPages, DocSelType);
	// удаляем файлы с дублирующимися именами при разных путях 
	MyGraphicsPages =  FindDuplicatesNames(MyGraphicsPages, mySelectedExt, myButFirstDotName);
	if (MyGraphicsPages.length == 0) 
		{
			alert (inScriptName + "\nNo Matching Links!");
			myDialog.destroy();
			exit();
		}
	// переподстановка выбранных файлов:
	var ResRelinkErr = mySelRelinkF(MyGraphicsPages, MyNDirAbsURI, mySelectedExt, MyStepByStepMode.checkedState, myClippPathNone.checkedState, myPossRotateIm.checkedState, myButFirstDotName, myChTransOp, myCenterContent.checkedState);
	// отчет 
	ResRelinkErr.push(myImagesWithANonpr);
	if (myShowReportRelink.checkedState == true) 
	ReportErrorsRelink(ResRelinkErr, inpVLinkStArr[myIndexButLinksSt][0], PRSedcont, PREedcont, SecNSelect, mySelSectPR, mySTdocStr);
	// выход
	myDialog.destroy();
	exit();
}

/* ФУНКЦИИ•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
/* Функция возвращает массив счетчиков изображений документа 
по состоянию связи с файлом.
Внедренные файлы предлагается извлечь в выбранную папку.
*/
function myDocLinksCounters(inDDoc)
{
	var aDocLinksL = inDDoc.links.length;
	var ArrLinksCount = new Array(0, 0, 0, aDocLinksL);
	var myEmbeddedLinks = new Array();
	for (var linkCounter = 0; linkCounter < aDocLinksL; linkCounter++){
			if (inDDoc.links[linkCounter].status == LinkStatus.linkMissing) ArrLinksCount[0]++;
			if (inDDoc.links[linkCounter].status == LinkStatus.normal) ArrLinksCount[1]++;
			if (inDDoc.links[linkCounter].status == LinkStatus.linkOutOfDate) ArrLinksCount[2]++;
			if (inDDoc.links[linkCounter].status == LinkStatus.linkEmbedded) myEmbeddedLinks.push(inDDoc.links[linkCounter]);}
	// для внедренных изображений 
	if (myEmbeddedLinks.length > 0){
			if(confirm ("Found " + myEmbeddedLinks.length + " embedded image(s).\nUnembed this file(s)?"))
				{	// выбор папки
					var myUnmDir = Folder.selectDialog("Select the Folder where files will be created.", inDDoc.filePath);
					if(myUnmDir != null) {
							var MyNewUnembedDir = myUnmDir.absoluteURI;  
							for (linkCounter = 0; linkCounter < myEmbeddedLinks.length; linkCounter++){	
									// если файл с таким же именем существует
									if (File(MyNewUnembedDir + "/" + myEmbeddedLinks[linkCounter].name).exists){ 
										if(confirm (myEmbeddedLinks[linkCounter].name + " already exist in the folder.\nDo you want to overwrite the file with the embedded data?"))
										{myEmbeddedLinks[linkCounter].unembed(Folder(MyNewUnembedDir)); ArrLinksCount[1]++;}}
									else {myEmbeddedLinks[linkCounter].unembed(Folder(MyNewUnembedDir)); ArrLinksCount[1]++;}}}}}
return ArrLinksCount;
}

/* Функция удаляет из массива myObjArray изображения с атрибутом "не печатать" 
при myNonPrImSeld = false. При пошаговом режиме предлагается снять атрибут "не печатать"
с изображений массива myObjArray. 
Формируется массив изображений с атрибутом "не печатать" myArrayNonprintingIm для отчета.
*/
function myPrint_ObjArray(myObjArray, myStepModeTrue, myNonPrImSeld, myArrayNonprintingIm) 
{
	var myPrintObjArray= new Array();
	var myObjPr;
	for (var myCobj = 0; myCobj < myObjArray.length; myCobj++) 
		{
			myObjPr = myObjArray[myCobj];
			if (myNonprint_ParentRe(myObjPr))
				{		
					if(myStepModeTrue == true)
						{
							myObjPr.itemLink.show();
							if (confirm("Non-printing Image: " + myObjPr.itemLink.name + "!\nSet attribute \"Nonprinting\" to Off?") == true)
								{
									myNonpFalse_ParentRe (myObjPr);
									myPrintObjArray.push(myObjPr);
								}
							else myArrayNonprintingIm.push(myObjPr.itemLink.name);
						} 
					else myArrayNonprintingIm.push(myObjPr.itemLink.name);
					if (myNonPrImSeld == true) myPrintObjArray.push(myObjPr);
				}	
			else myPrintObjArray.push(myObjPr);
		}
return myPrintObjArray;
}

/* Функция возвращает массив изображений, выбранных 
по состоянию связи c файлом из массива myImagesArray, 
*/
function selMissNormModAll_Links(myImagesArray, LinksStatusIndex, atrNonPrint) 
{
	if(LinksStatusIndex == 3) return myImagesArray;
	var myStatusImages = new Array();
	var myStatusLink;	
	for (var myCounter = 0; myCounter < myImagesArray.length; myCounter++) 
		{
			myStatusLink = myImagesArray[myCounter].itemLink.status; 
			// отсутствующие
			if(myStatusLink == LinkStatus.linkMissing & LinksStatusIndex == 0) 
			myStatusImages.push(myImagesArray[myCounter]);
			// нормальные
			if(myStatusLink == LinkStatus.normal & LinksStatusIndex == 1) 
			myStatusImages.push(myImagesArray[myCounter]);
			// модифицированные
			if(myStatusLink == LinkStatus.linkOutOfDate & LinksStatusIndex == 2) 
			myStatusImages.push(myImagesArray[myCounter]);
		}	
return myStatusImages;
}

/* Функция "перелинковки" выбранных изображений.
Возвращает массив с результатами замещения.
*/
function mySelRelinkF(MySeldGraphics, MyRFolder, myExten, StepModeTrue, ClipPathNone, ChRotate, mySelDotFirst, myTrsOp, fitCenterCont)
{
	var myLink;
	var myNewLinkName;
	var myFileName;	
	var myFileNameNoExt;	
	var myRelinkFileName;	
	var myUpdLink;
	var RelinkYes = true;
	var ReportAlerts = new Array();
	var mySeccessRelinks = new Array();
	var DuplicatsCancelObj = new Array();
	var NoFileExistErrorLinks = new Array();
	var CancelByURelink = new Array();
	var RelinkToFilesName;
	var OldGeomBounds;
	var myCountUndo;
	var myImageRotAng;
	var myImageShAngl;
	var myPossAngleW;
	var myNewFImage;
	var myPrSc;
	var myNewPrSc;
	var myIsImagePar = new Array();
	var myBlendingSettings = "";
	// считать координаты для разворота
	app.activeDocument.viewPreferences.rulerOrigin = RulerOrigin.spreadOrigin;
	// установка центральной точки (для поворота изображения)
	app.activeWindow.transformReferencePoint = AnchorPoint.centerAnchor;
	for (var i = 0; i < MySeldGraphics.length; i++) 
		{	
			if (MySeldGraphics[i][1] == true)
				{	
					myLink = MySeldGraphics[i][0].itemLink;
					myFileName = myLink.name;
					myFileNameNoExt = FileNameWtExt(myFileName, mySelDotFirst);		
					
					if (myExten == nameNCE) myRelinkFileName = myFileName;
					else myRelinkFileName = myFileNameNoExt + "." + myExten;	
					// полное имя файла
					myNewLinkName = MyRFolder + "/" + myRelinkFileName;
					// переменная, описывающая операцию замещения файлов
					if (mySelDotFirst == false) RelinkToFilesName = myFileName + " to \'" + myExten + "\'";
					else RelinkToFilesName = myFileName + " to " + myRelinkFileName;
					// если файл найден 
					if (File(myNewLinkName).exists == true)
						{
							// запоминаем координаты предварительного изображения
							OldGeomBounds = MySeldGraphics[i][0].geometricBounds;
							// для пошагового режима
							if(StepModeTrue == true) 
								{	
									myLink.show();
									// blending settings
									if (myTrsOp == true) {myBlendingSettings = OBJ_Effects(MySeldGraphics[i][0], InDver.substr(0,1));}
									RelinkYes = confirm ( "Relink: " + RelinkToFilesName + "?\n\n" + myBlendingSettings);
									if (RelinkYes)
										{
											// Запоминаем параметры предварительного изображения
											myIsImagePar = [MySeldGraphics[i][0].horizontalScale, MySeldGraphics[i][0].verticalScale, MySeldGraphics[i][0].shearAngle, MySeldGraphics[i][0].rotationAngle, OldGeomBounds];
											// отношение горизонтального и вертикального масштабов
											myPrSc = ScaleProp_HV(MySeldGraphics[i][0]);
										}
								}	
							if (RelinkYes)
								{
									myLink.relink(File(myNewLinkName));
									myUpdLink = myLink.update();
									myNewFImage = myUpdLink.parent;
									myNewFImage.geometricBounds = OldGeomBounds;
									myCountUndo = 3;
									// для пошагового режима
									if(StepModeTrue == true)	
										{
											if (ClipPathNone == true) 
												{
													if (myUpdLink.parent.clippingPath.clippingType != ClippingPathType.none) 
													{myUpdLink.parent.clippingPath.clippingType = ClippingPathType.none; myCountUndo++;}
												}
											myUpdLink.show();
											if(ChRotate == true)
												{
													// анализ вероятности поворота изображения (±90°)
													myNewPrSc = ScaleProp_HV(myNewFImage);
													if (myNewPrSc - myPrSc > myVGScDop | myNewPrSc - myPrSc < -myVGScDop)
														{	
															// Функция поворота изображения
															if(InDver == 4) myCountUndo = myRotateDialogCS2 (myNewFImage, myIsImagePar, myCountUndo);
															else myCountUndo = myRotateUIDialog (myNewFImage, myIsImagePar, myCountUndo);
														}
												}
											// изменение размеров изображения
											if (fitCenterCont == true) {myCountUndo = im_fitCenter100 (myNewFImage, myCountUndo);}
											else {myCountUndo = Scale_VH (myNewFImage, myPrSc, myCountUndo);}		
											// применить изменения изображения
											if (confirm ("Apply Changes?") == false)
												{
													myResUndo(myCountUndo);
													CancelByURelink.push(RelinkToFilesName);
													if (confirm ("Continue Relink Files?") == false) break;
												} else mySeccessRelinks.push(RelinkToFilesName);
										} else mySeccessRelinks.push(RelinkToFilesName);
								} else CancelByURelink.push(RelinkToFilesName);
						} else NoFileExistErrorLinks.push(RelinkToFilesName);
				} else {if (myExten != nameNCE) DuplicatsCancelObj.push(myFileNameNoExt); else DuplicatsCancelObj.push(myFileName);}
		} // завершение цикла
	ReportAlerts.push(mySeccessRelinks);
	ReportAlerts.push(NoFileExistErrorLinks);
	ReportAlerts.push(DuplicatsCancelObj);
	ReportAlerts.push(CancelByURelink);
	ReportAlerts.push(MySeldGraphics.length);
	ReportAlerts.push(myExten);
	ReportAlerts.push(MyRFolder);
return ReportAlerts;
}

/* Функция формирует отчет по замещению фйлов изображений документа. */
function ReportErrorsRelink (ArrErrorsLinks, myFoundSt, DnStPage, DnEndPage, DnNSec, SelSecY, TypeDocSel)
{
	var myReportRelnk = app.dialogs.add({name: "Change Links Report:", canCancel: false});
	var myFragmD = myReportRelnk.dialogColumns.add().borderPanels.add().dialogColumns.add();
	with (myFragmD) 
		{	
			var myEndRT;
			var myBegRT;
			if (ArrErrorsLinks[5]  == nameNCE) myEndRT = " to " + ArrErrorsLinks[5] + " names";
			else myEndRT = " to " + "\"" + ArrErrorsLinks[5] + "\" type";
			if (myFoundSt != "All Links") myBegRT = "With status \"" + myFoundSt + "\"";
			else myBegRT = myFoundSt ;
			// формируем отчет
			staticTexts.add({staticLabel:"Total: " + ArrErrorsLinks[4] + " Links Found"});	
			with (borderPanels.add())
				{	
					staticTexts.add({staticLabel: myBegRT, minWidth: 230});	
					dropdowns.add({stringList: TypeDocSel, selectedIndex: 0, minWidth: 130});
					staticTexts.add({staticLabel: myEndRT, minWidth: 120});	
					staticTexts.add({staticLabel:"", minWidth: 55});	
				}
			var StLabelsArr = new Array();
			StLabelsArr = ["successfully relink", "links to not existing files", "ignored links with duplicates of names", "canceled by user", "with attributes \"Nonprinting\""];
			for (myBordersCount = 0; myBordersCount <  StLabelsArr.length; myBordersCount++) 
			if (myBordersCount <4)
				{
					BorderTextsDropdowns (myFragmD, StLabelsArr[myBordersCount], ArrErrorsLinks[myBordersCount], 230);	
				}
			else 
				{	
					var mySecSelInfo;
					if(SelSecY == true) 
					mySecSelInfo = " of section #" + (DnNSec+1); 
					else 
					mySecSelInfo = " of document";
					dialogRows.add().staticTexts.add({staticLabel:"Range of pages: " + DnStPage + " – " + DnEndPage + mySecSelInfo});	
					BorderTextsDropdowns (myFragmD, StLabelsArr[myBordersCount], ArrErrorsLinks[7], 230);	
				}		
			dialogRows.add().staticTexts.add({staticLabel:"Folder: \"" + Folder.decode(Folder(ArrErrorsLinks[6]).name) + "\""});	
		}
	myReportRelnk.show();
	myReportRelnk.destroy();
}

/* Функция формирует панель диалога с текстовой информацией
и "выпадающим списком" неповторяющихся объектов массива myArray.
*/
function BorderTextsDropdowns (myDialogArh, StrTextLabel, myArray, DdownsMinimW)
{
	if (myArray.length > 0)
	with (myDialogArh.borderPanels.add())
		{
			staticTexts.add({staticLabel: myArray.length + " " + StrTextLabel + ":", minWidth: DdownsMinimW});	
			dropdowns.add({stringList: myArray, selectedIndex: 0, minWidth: 320});
		}
}

/* Функция возвращает массив графических объектов
заданного диапазона страниц  документа.
*/
function RangePagesGraphics (mySegDoc, StartEC, EndgEC, SNSel, SecStart, SecEnd)
{
	var NPageStart = -1; 
	var CurrtPage;
	var myGaphicsCounter;
	var MyGraphicsP = new Array();
	var MyGraphicsPFinal = new Array();
	var myLinkType;
	// для диапазона страниц документа
	for(var myPageCounter = SecStart; myPageCounter <  SecEnd; myPageCounter++) 
		{
			CurrtPage = mySegDoc.pages[myPageCounter];	
			if(StartEC == CurrtPage.name) NPageStart = CurrtPage.name;	
			if(NPageStart != -1) 
				{
					// дополняем массив графическими объектами страницы
					for(myGaphicsCounter = 0; myGaphicsCounter <  CurrtPage.allGraphics.length; myGaphicsCounter++) 
					if (CurrtPage.allGraphics[myGaphicsCounter].itemLink != null) MyGraphicsP.push(CurrtPage.allGraphics[myGaphicsCounter]);
				}				
			// если имя текущей и финальной в диапазоне совпадают, то выходим из цикла
			if(EndgEC == CurrtPage.name)  break;
		}
	EndgEC = CurrtPage.name; 
	/* если не найдена первая страница в диапазоне, 
	то считаем, что диапазон внутри секции задан неправильно,
	заполняем массив графическими объектами выбранной секции */
	if(SNSel == true & NPageStart == -1)
		{ 
			NPageStart = mySegDoc.pages[SecStart].name;
			for(myPageCounter = SecStart; myPageCounter <  SecEnd; myPageCounter++) 
				{
					CurrtPage = mySegDoc.pages[myPageCounter];	
					// дополняем массив графическими объектами страницы
					for(myGaphicsCounter = 0; myGaphicsCounter <  CurrtPage.allGraphics.length; myGaphicsCounter++) 
					if (CurrtPage.allGraphics[myGaphicsCounter].itemLink != null) MyGraphicsP.push(CurrtPage.allGraphics[myGaphicsCounter]);
				}
			EndgEC = CurrtPage.name;
		}
	MyGraphicsPFinal.push(MyGraphicsP);
	MyGraphicsPFinal.push(NPageStart);
	MyGraphicsPFinal.push(EndgEC);
return MyGraphicsPFinal;
}

/* Функция возвращает массив параметров секций документа.
ArrFSecPageNumbers [section number][0] - порядковый номер первой страницы секции,
ArrFSecPageNumbers [section number][1] - "true" - включать префикс секции при нумерации,
ArrFSecPageNumbers [section number][2] - префикс секции,
ArrFSecPageNumbers [section number][3] - номер первой страницы секции,
ArrFSecPageNumbers [section number][4] - количество страниц в секции.
*/
function SecRangeOfPages (myDocument)
{
	var mySecEnd = 0;
	var ArrFSecPageNumbers = new Array();
	var SectionOfPage = myDocument.pages[0].appliedSection;
	var SecPrefixName = SectionOfPage.sectionPrefix;
	var SecPnumStart =  SectionOfPage.pageNumberStart;
	var SecIncludePrfx = SectionOfPage.includeSectionPrefix;
	ArrFSecPageNumbers.push([0, SecIncludePrfx, SecPrefixName, SecPnumStart, 0]);
	for(var myPageCounter = 0; myPageCounter <  myDocument.pages.length; myPageCounter++) 
		{	
			CurrentSection = myDocument.pages[myPageCounter].appliedSection;
			if(SectionOfPage != CurrentSection) 
				{
					SecPrefixName = CurrentSection.sectionPrefix;
					SecPnumStart =  CurrentSection.pageNumberStart;
					SecIncludePrfx = CurrentSection.includeSectionPrefix;
					ArrFSecPageNumbers[ArrFSecPageNumbers.length-1][4] = mySecEnd;
					mySecEnd = 0;
					ArrFSecPageNumbers.push([myPageCounter, SecIncludePrfx, SecPrefixName, SecPnumStart, mySecEnd]);
					SectionOfPage = CurrentSection;	
				}
			mySecEnd++;
		}
	ArrFSecPageNumbers[ArrFSecPageNumbers.length-1][4] = mySecEnd;
return ArrFSecPageNumbers;
}

/* Функция удаления папок и системных файлов 
из массива объектов выбранной папки.
Возвращает массив типов файлов (расширений).
*/
function ExtenSysCheck (ArrayFilesExt)
{
	var GrFilesExtArr = new Array();
	var CurrFile;
	for (var myCr = 0; myCr < ArrayFilesExt.length; myCr++) 
		{
			CurrFile = ArrayFilesExt[myCr];
			// не папка, не системный файл
			if (typeof CurrFile.open != "undefined" && !MacOsXSysFile(CurrFile))
			GrFilesExtArr.push(FileNExt(CurrFile));
		}	
	GrFilesExtArr = getUniqObjArray(GrFilesExtArr);
return GrFilesExtArr;
}

/* Функция определения "системного файла" по расширению, 
если имя файла начинается с точки, 
то определяем его как системный файл (для Mac OS X).
*/
function MacOsXSysFile(FileNamePath) 
{
	var myFileNamePath = String(FileNamePath);
	var EndFullPath = myFileNamePath.lastIndexOf("/");
	var myFileFirstT = myFileNamePath.substr(EndFullPath+1, 1);
	if (myFileFirstT == ".") return true;
	var ExtCurrFile = FileNExt(myFileNamePath);
	if(ExtCurrFile.length > 2 & ExtCurrFile.length < 5)
		{
			var SysExtArr = new Array("DAT","VOL","APP","INI","SYS","COM","BAT","BAK",
			"ATM","TMP","DLL","REG","OLD","LOG","CFG","JSX","OTF","PFB","PFM","TTF","FON","LNK","EXE");
			for (var extCr = 0; extCr < SysExtArr.length; extCr++) 
			if (ExtCurrFile == SysExtArr[extCr] | ExtCurrFile == SysExtArr[extCr].toLowerCase()) return true;
		}
	else return true;
return false;
}

/* Функция проверки дубликатов имен файлов 
(с расширением - при замене на идентичный тип или без расширения). 
Возвращает массив графических объектов с "разрешением замены" - ArrayGraphObjReLinksSt.
Игнорируются файлы с дублирующимися именами: 
с расширением - при замене на тип файлов "идентичный", 
без расширения - при замене на выбранный тип, при отличающихся полных именах файлов.
*/
function FindDuplicatesNames (ArrayGraphObj, myextSel, DotFirst)
{
	var NameNoExt;
	var NameNoExtArr = new Array();
	var ArrayGraphObjReLinksSt = new Array();
	var IndFD = new Array();
	// заполняем массив имен файлов
	for (var myCr = 0; myCr < ArrayGraphObj.length; myCr++) 
		{
			if (myextSel != nameNCE) NameNoExt = FileNameWtExt(ArrayGraphObj[myCr].itemLink.name, DotFirst);
			else NameNoExt = ArrayGraphObj[myCr].itemLink.name;
			NameNoExtArr.push(NameNoExt);
		}
	for (myCr = 0; myCr < ArrayGraphObj.length; myCr++) 
		{
			var PathExtArr = new Array();
			IndFD = checkDoubled(NameNoExtArr, NameNoExtArr[myCr]);
			if( IndFD.length > 1)
				{
					for (var myDuplidx = 0; myDuplidx < IndFD.length; myDuplidx++) 
					{PathExtArr.push(ArrayGraphObj[IndFD[myDuplidx]].itemLink.filePath);}
					if(getUniqObjArray(PathExtArr).length == 1) 
					ArrayGraphObjReLinksSt.push([ArrayGraphObj[myCr], true]);
					else 
					ArrayGraphObjReLinksSt.push([ArrayGraphObj[myCr], false]);
				}
			else ArrayGraphObjReLinksSt.push([ArrayGraphObj[myCr], true]);
		}
return ArrayGraphObjReLinksSt;
}

/* Функция определения расширения файла, 
т.е. возвращает часть строки от крайней правой точки. 
*/
function FileNExt(FileNamePath) 
{
	var myFileNamePath = String(FileNamePath);
	var myString = "";
	var myFileNEnd = myFileNamePath.lastIndexOf(".");
	if (myFileNEnd != -1) 
	myString = myFileNamePath.substr(myFileNEnd+1);
	else myString = myFileNamePath;
return myString;
}

/* Функция удаляет расширение файла,
возвращает строку от начала myFileName до первого (при myDotOrd = true)
или последнего символа точки (myDotOrd = false).
*/
function FileNameWtExt (myFileName, myDotOrd) 
{
	var myFileNamePath = String(myFileName);
	var myString = "";
	var myFileNEnd = myFileNamePath.lastIndexOf(".");
	if (myFileNEnd != -1) 
		{
			if (myDotOrd == true)
			// рекурсивный вызов функции
			myString = FileNameWtExt(myFileName.substr(0, myFileNEnd), true);
			else 
			myString = myFileName.substr(0, myFileNEnd);
		}
	else myString = myFileNamePath;
return myString;
}

/* Функция получения массива типов графических файлов, которые 
используются в документе (ActDoc).
Выполняется Unlock Position для всех объектов и групп с графическими 
изображениями документа. Определяется количество изображений, 
которые были вставлены в документ из буфера обмена (отсутствует Link).
*/
function GetFileTypeInDoc (ActDoc)
{
	var myObject;
	var myImageType;
	var myDocTypeArr = new Array();
	var myDocUniqTypeArr;
	var myResultDocTypeAndCounters = new Array();
	for (myCr = 0; myCr < ActDoc.allGraphics.length; myCr++) 
		{
			myObject = ActDoc.allGraphics[myCr];
			myUnlock_ParentRe (myObject);
			try
				{
					myImageType = myObject.itemLink.linkType;
					myDocTypeArr.push(myImageType);
				}
			catch(e) 
				{
					mySelection_ParentRe(myObject, myObject);
					if(confirm(myObject.constructor.name + " without link! \n(imported from clipboard)\nContinue?") == false) exit();
				}
		}
	myDocUniqTypeArr = getUniqObjArray(myDocTypeArr);
	for (myCr = 0; myCr < myDocUniqTypeArr.length; myCr++) 
	myResultDocTypeAndCounters.push([myDocUniqTypeArr[myCr], checkDoubled(myDocTypeArr, myDocUniqTypeArr[myCr]).length]);	
return myResultDocTypeAndCounters;
}

/* Функция осуществляет переход в активном окне на разворот 
с объектом myGraphObj и выделяет mySelectObj, 
если обект не является содержимым текстового блока. */
function mySelection_ParentRe (myGraphObj, mySelectObj) 
{	
	app.activeDocument.select(mySelectObj);
	app.activeWindow.zoom(2053206906);
	if (myGraphObj.parent.constructor.name != "Story"){
	try {app.activeWindow.activeSpread = myGraphObj.parent;}
	// рекурсивный вызов при ошибке
	catch (e) {mySelection_ParentRe(myGraphObj.parent, mySelectObj);}}
}

// Функция выполняет UnLock Positon изображения myGraphObj
function myUnlock_ParentRe (myGraphObj)
{
	try {myGraphObj.parent.locked = false;}
	// рекурсивный вызов при ошибке
	catch (e) {myUnlock_ParentRe(myGraphObj.parent);}
}

/* Функция выполняет поиск "истинности" атрибута Nonprinting 
для изображения и групп, включающих текущий объект */
function myNonprint_ParentRe (myGraphNObj)
{
	try 
	{	
		var mNonPrRes = myGraphNObj.nonprinting;
		// условие рекурсивного вызова функции
		if (mNonPrRes == false) 
			{
				mNonPrRes = myNonprint_ParentRe(myGraphNObj.parent);
				if(mNonPrRes == true) return true;
			}
		else return true;
	} 	
catch (e) {return false;} 
}

/* Функция отменяет "истинность" атрибута Nonprinting 
для изображения, его контейнера и групп, включающих текущий объект */
function myNonpFalse_ParentRe (myGraphFObj)
{
	try {	
		myGraphFObj.nonprinting = false;
		myNonpFalse_ParentRe(myGraphFObj.parent);} 
	catch (e) {} 
}

/* Функция поиска дубликата myObject в массиве myArray. Возвращает массив индексов найденных дубликатов в массиве. */
function checkDoubled(myArray, myObject) 
{
	var IndxDupls = new Array(); 
	for (var objCnr = 0; objCnr < myArray.length; objCnr++) 
	if (myObject == myArray[objCnr]) IndxDupls.push(objCnr);
return IndxDupls;
}

/* Функция возвращает массив myResultArr из неповторяющихся объектов массива myArray. */
function getUniqObjArray(myArray) 
{
	var myResultArr = new Array();
	var myObject;
	for (var myCounter = 0; myCounter < myArray.length; myCounter++) 
	{
		myObject = myArray[myCounter];
		if (checkDoubled(myResultArr, myObject).length == 0) myResultArr.push(myObject);
	}
return myResultArr;
}
function cr()
{if (mn != "\u00A9\ \u0044\u006D\u0069\u0074\u0072\u0069\u0079\ \u004C\u0061\u0070\u0061\u0065\u0076") exit();}

/* Функция получения графических объектов выбранных типов (ArrTypeFind)
из массива (myRastrImageArray).
*/
function getTypeRastrImages (myRastrImageArray, ArrTypeFind)
{
	var myTypeResult = new Array();
	var myObject;
	var myTypeImage;
	for (var myCounter = 0; myCounter < myRastrImageArray.length; myCounter++) 
	{
		myObject = myRastrImageArray[myCounter];
		myTypeImage = myObject.itemLink.linkType;
		for (var TypeCr = 0; TypeCr < ArrTypeFind.length; TypeCr++) 
		if (myTypeImage == ArrTypeFind[TypeCr][1] & ArrTypeFind[TypeCr][0] == true) 
		myTypeResult.push(myObject);	
	}
return myTypeResult;
}

/* Функция поворота изображения myRImage на 90° по часовой стрелке или против,
в диалоге выбирается направление вращения. После вращения:
изображению присваиваются значения geometricBounds исходного, 
возвращается счетчик действий над изображением - myCountNone.
myImageArrPars  (horizontalScale, verticalScale, shearAngle, rotationAngle, geometricBounds).
*/
function myRotateUIDialog(myRImage, myImageArrPars, myCountNone)
{
	// Прогнозирование возможного поворота изображения при обработке
	var myPossAngleW = true;
	if (myImageArrPars[3] >= 90) myPossAngleW = false;
	// Создаем диалог
	var myR_Dialog = new Window('dialog', myRImage.itemLink.name);
	with(myR_Dialog)
		{
			orientation = 'column';
			var myRotatePanel = add('panel', undefined, "Rotate:");
			with(myRotatePanel)
				{
					orientation = 'row';
					margins = [15, 15, 15, 15];
					spacing = 10;
					myR_Dialog.myRotateCCWRadioButton = add('radiobutton', undefined, "90° CCW");
					if (myPossAngleW == true) myR_Dialog.myRotateCCWRadioButton.value = true;
					myR_Dialog.myRotateCWRadioButton = add('radiobutton', undefined, "90° CW");
					if (myPossAngleW == false) myR_Dialog.myRotateCWRadioButton.value = true;
				}
			with(add('group'))
				{
					orientation = 'row';
					spacing = 15;
					myR_Dialog.myOKButton = add('button',[0,0,80,25], "OK", {name:'ok'});
					myR_Dialog.myCloseButton = add('button', [0,0,80,25], "Cancel", {name:'cancel'});
					myR_Dialog.myCloseButton.onClick = function(){myR_Dialog.close()};
				}
		}
	var myReturn = myR_Dialog.show();
	if (myReturn == true)
		{	// вращение изображения
			if (myR_Dialog.myRotateCWRadioButton.value ==  true)
			myRImage.rotationAngle = myImageArrPars[3] - 90;		
			else myRImage.rotationAngle = myImageArrPars[3] + 90;		
			// перестановка вертикального и горизонтального масштабов
			myRImage.horizontalScale = myImageArrPars[1];
			myRImage.verticalScale = myImageArrPars[0];
			myRImage.shearAngle = myImageArrPars[2];
			myCountNone += 4;
			// shear angle
			if (myImageArrPars[2] >= 0.1 | myImageArrPars[2] <=  - 0.1)
				{
					if(confirm("The skewing angle applied to the Image is " + String(myImageArrPars[2]) .substr(0,3) + "°.\nAfter rotate this value is incorrect!\nSet Shear Angle to 0°?") == true) 
						{
							myRImage.shearAngle = 0;
							myCountNone ++;
						}
				}
			// присваиваем координаты исходного изображения
			myRImage.geometricBounds = myImageArrPars[4];
			myCountNone ++;
		}
	myR_Dialog.close();
return myCountNone;
}

function myRotateDialogCS2(myRImage, myImageArrPars, myCountNone)
{
	// Прогнозирование возможного поворота изображения при обработке
	var myPossAngleW = true;
	if (myImageArrPars[3] >= 90) myPossAngleW = false;
	// Создаем диалог
	var myR_Dialog = app.dialogs.add({name:myRImage.itemLink.name});
	with(myR_Dialog.dialogColumns.add().borderPanels.add().dialogColumns.add()) 
		{		
			dialogRows.add().staticTexts.add({staticLabel:"Rotate:"});
			with(borderPanels.add().dialogColumns.add()) 
				{
					var myRotateRadioButton = radiobuttonGroups.add();			
					myRotateRadioButton.radiobuttonControls.add({staticLabel:"90° CW", checkedState:!myPossAngleW,minWidth:50});
					myRotateRadioButton.radiobuttonControls.add({staticLabel:"90° CCW", checkedState:myPossAngleW});
				}
		}
	var myReturn = myR_Dialog.show();
	if (myReturn == true)
		{	// вращение изображения
			if (myRotateRadioButton.selectedButton == 0) 
			myRImage.rotationAngle = myImageArrPars[3] - 90;		
			else myRImage.rotationAngle = myImageArrPars[3] + 90;		
			// перестановка вертикального и горизонтального масштабов
			myRImage.horizontalScale = myImageArrPars[1];
			myRImage.verticalScale = myImageArrPars[0];
			myRImage.shearAngle = myImageArrPars[2];
			myCountNone += 4;
			// shear angle
			if (myImageArrPars[2] >= 0.1 | myImageArrPars[2] <=  - 0.1)
				{
					if(confirm("The skewing angle applied to the Image is " + String(myImageArrPars[2]) .substr(0,3) + "°.\nAfter rotate this value is incorrect!\nSet Shear Angle to 0°?") == true) 
						{
							myRImage.shearAngle = 0;
							myCountNone ++;
						}
				}
			// присваиваем координаты исходного изображения
			myRImage.geometricBounds = myImageArrPars[4];
			myCountNone ++;
		}	
	myR_Dialog.destroy();
return myCountNone;
}

/* Функция получения отношения горизонтального и вертикального 
масштабов изображения.
*/
function ScaleProp_HV(myImage)
{
	var myImageHorzSc = myImage.horizontalScale;
	var myImageVertSc = myImage.verticalScale;
	// Отношение горизонтального и вертикального масштабов
	var myOtnAbsSc = myImageHorzSc / myImageVertSc;
return myOtnAbsSc;
}

/* Функция округления параметров изображения. */
function Scale_VH(SclImage, OtnshBasHVsc, CountUndo)
{
	var SclImageHorzSc = SclImage.horizontalScale;
	var SclImageVertSc = SclImage.verticalScale;
	if (OtnshBasHVsc > 0.9999 & OtnshBasHVsc < 1.0001 & OtnshBasHVsc != 1)
		{
				if (SclImageHorzSc >= SclImageVertSc) SclImage.verticalScale = SclImageHorzSc;
				else SclImage.horizontalScale = SclImageVertSc;
				CountUndo++;
		}
	var SclImageShAng = SclImage.shearAngle;
	if (Math.abs (SclImageShAng) < 0.1 & SclImageShAng != 0) {SclImage.shearAngle = 0; CountUndo++;}
return CountUndo;
}

/* Функция анализа  установок прозрачности.
Анализируется непрозрачность (Opacity) и режимы наложения (Blending Mode).
Возвращает текстовую информацию установок прозрачности изображения и его контейнера
при условиях: Opacity < 100% или Blending Mode - не "Normal".
*/
function OBJ_Effects (TranspCh_obj, myInDesignversion)
{
	var TranspSetStr = "";
	if (myInDesignversion != 4)
		try
			{
				var eff_obj = TranspCh_obj.transparencySettings.blendingSettings;
				var ImageBMode = eff_obj.blendMode;
			} catch(e){return TranspSetStr;}
	else 
		try
			{
				var eff_obj = TranspCh_obj;
				var ImageBMode = eff_obj.blendMode;
			} catch(e){return TranspSetStr;}
	var ImageOpac = eff_obj.opacity;
	var IBl = eff_obj.isolateBlending;
	var KG = eff_obj.knockoutGroup;
	if (IBl == true) IBl = "Yes"; else IBl = "No";
	if (KG == true) KG = "Yes"; else KG = "No";
	// Заполняем массив значений Blending Mode
	var MBlendMods = new Array([1852797549, "Normal"], [2020625762, "Multiply"], [2020625763, "Screen"], [2020625764, "Overlay"], 
	[2020625765, "Soft Light"], [2020625766, "Hard Light"], [2020625767, "Color Dodge"], [2020625768, "Color Burn"], [2020625769, "Darken"], 
	[2020625770, "Lighten"], [2020625771, "Difference"], [2020625772 , "Exclusion"], [2020625773, "Hue"], [1380545377, "Saturation"], 
	[1668246642, "Color"], [2020625776, "Luminosity"]);
	// проверка Opacity и Blending Mode 
	if (ImageBMode != 1852797549 | ImageOpac != 100)
		{
			for (var bm = 0; bm < MBlendMods.length; bm++) 
			if (ImageBMode == MBlendMods[bm][0]) var bmText = MBlendMods[bm][1];		
			TranspSetStr += TranspCh_obj.constructor.name + ":\n● Opacity: " + ImageOpac + "%\n● Blending Mode: \"" + bmText + 
			"\"\n● Isolate Blending: " + IBl + "\n● Knockout Group: " + KG + "\n";
		}
	// рекурсивный вызов
	TranspSetStr += OBJ_Effects (TranspCh_obj.parent, myInDesignversion);
return TranspSetStr;
}

/* Функция выбирает в строке myStringSkbk текст в круглых скобках */
function Str_inskbk(myStringSkbk)
{
	var myInSkbkString = String(myStringSkbk);
	var myStrBeg = myInSkbkString.lastIndexOf("(");
	if (myStrBeg != -1) 
		{
			myInSkbkString = myInSkbkString.substr(myStrBeg+1);
			var myStrEnd = myInSkbkString.lastIndexOf(")");
			if (myStrEnd != -1) myInSkbkString = myInSkbkString.substr(0, myStrEnd);
		}
return myInSkbkString;
}

/* Функция установки параметров изображения: углы - 0°, масштаб - 100 %, по центру фрейма. */
function im_fitCenter100 (myImageUpD, cntUndo)
{					
	if (myImageUpD.rotationAngle != 0) {myImageUpD.rotationAngle = 0; cntUndo++;}
	if (myImageUpD.shearAngle != 0) {myImageUpD.shearAngle = 0; cntUndo++;}
	if (myImageUpD.verticalScale != 100) {myImageUpD.verticalScale = 100; cntUndo++;}
	if (myImageUpD.horizontalScale != 100) {myImageUpD.horizontalScale = 100; cntUndo++;}
	myImageUpD.fit (FitOptions.centerContent); cntUndo++;
return cntUndo;
}

/* Функция отмены действий в документе (undo),
отменяется количество действий равное счетчику CPtoN.
*/
function myResUndo(CPtoN)
{for (var cUndo = 0; cUndo < CPtoN; cUndo++) app.activeDocument.undo();}

//09.02.2008