Этот выпуск серии статей о скриптах посвящён утилитам — небольшим программкам-помощникам, помогающим в решении рутинных задач.
ZOOM TO FIT
По опыту могу сказать: при переходе от Corel DRAW к Illustrator на первых порах не хватало возможности увеличивать масштаб изображения так, чтобы выделенный объект занимал весь экран (в CorelDRAW операция Zoom to Fit). Она очень удобна при редактировании сложной композиции, когда часто переключаешься из одного масштаба в другой. В Illustrator это менее комфортно и удаётся лишь после обводки нужной области документа вручную, предварительно переключившись на инструмент Zoom.
Частичное решение: сохранить установки активного вида (масштаба и центра видимой зоны) как атрибуты документа — ViewёNew View. Но есть серьёзный недостаток, особенно при работе с объёмными макетами. Ведь создание «видов» для просмотра всех значимых объектов увеличенными вряд ли будет эффективным. Попробуем решить задачу с помощью сценария.
Анализируй это
Конкретизируем задание: быстро и в максимальном размере отображать любое количество выделенных объектов. Вопрос номер один — скорость. Быстрейшее выполнение всякой команды (а запуск сценария ничем, по сути, не отличается от остальных команд) — с помощью «горячих» клавиш. Как известно, в Illustrator СS клавиатурные эквиваленты назначаются не только пунктам меню, но даже пользовательским сценариям (EditёKeyboard ShortcutsёMenu CommandsёFileёScripts). В нашем случае — как нельзя кстати!
Но для увеличения объектов до размера экрана надо менять масштаб их отображения. Обзор документации по скриптингу на эту тему дал следующий результат: единственное, что нам доступно, — использовать специальный объект View. Он поддерживает метод Zoom, в качестве параметров которого — масштабирующие коэффициенты в обоих направлениях (по горизонтали и вертикали). Следовательно, вместо них должны выступать соответствующие соотношения размеров экрана и выделенного объекта. А всю информацию о нём мы получим без проблем — в скриптинге для этого масса возможностей. Остаётся разобраться с экраном.
Его размер определяется количеством элементов разложения (пикселей) в обоих направлениях и зависит от разрешения видеокарты. Чем больше физические размеры экрана, тем, как правило, выше установлено разрешение, которое может колебаться от 1024x768 до 1920x1440 (мы это должны учитывать). К сожалению, определить текущее разрешение графического адаптера напрямую через механизм скриптинга нельзя. Можно остановиться на распространённом 1024x768, но решение не будет универсальным, поскольку потребует коррекции для других случаев. Как же быть?
Чтобы не привязываться к конкретным значениям, пойдём на хитрость: принудительно установим масштаб отображения документа 100% и через свойство bounds объекта View узнаем размеры видимой зоны, связанной с текущим разрешением экрана. Поскольку единицы измерения в Illustrator CS действуют глобально и по умолчанию равны пунктам, метод bounds выдаст результат в этих же величинах, и не придётся ломать голову, как перейти к пунктам от пикселей, традиционно использующихся для задания размера экрана.
Итак, анализ показал, что создание скрипта осуществимо. Вперёд!
Определение размеров габаритного прямоугольника
Работай мы только с одним объектом, можно было сразу использовать его габариты для определения коэффициента увеличения. Однако нам придётся научить скрипт корректно взаимодействовать с любым количеством выделенных элементов. Для этого будем по очереди перебирать их и у каждого определять координаты крайних точек — левой, правой, верхней и нижней. Затем найдём координату самой левой, самой правой, верхней и нижней. Так и получим размеры искомого габаритного прямоугольника.
Поскольку для работы скрипта критически важно наличие хотя бы одного выделенного объекта, застрахуемся (прекращаем дальнейшие действия в случае, если ничего не выделено):
if (sel == 0) { alert («Select the target object!») }
Если же выделение есть, в цикле считываем координаты всех входящих в него объектов. При этом воспользуемся методом geometricBounds, выдающим все необходимые значения в виде массива в таком порядке: под номером 0 — координата крайней левой точки объекта; 1 — крайней верхней; 2 и 3 — самой правой и нижней.
else { for (i=0; i{- currL = sel[i].geometricBounds[0];
- currT = sel[i].geometricBounds[1];
- currR = sel[i].geometricBounds[2];
- currB = sel[i].geometricBounds[3];
}Начальные буквы curr в названии переменной говорят о том, что она определяет свойства текущего объекта. Но на этом цикл не заканчивается: будем использовать его для одновременного поиска самых крайних точек выделенного блока, сравнивая соответствующие координаты текущего и предыдущего объектов. Если самая левая точка (currL) окажется левее, чем была зафиксирована ранее (т. е. имеет наименьшее значение по оси Х из всех проверенных объектов), будем считать её новой границей в данном направлении (maxL). Если же порог не достигнут, левый край остаётся прежним. Соответственно, нижней границей блока станет точка (currB) с минимальным положением на оси Y (maxB).
Для остальных направлений всё наоборот: верхней границей (maxT) будет точка, координата которой (currT) по оси Y наибольшая, а правую границу определит точка с максимальным значением по оси Х. Выполняя такие операции в цикле для всех задействованных объектов, мы точно определим координаты габаритных точек.
if (currL < maxL) { maxL = currL }
if (currB < maxB) { maxB = currB }
if (currT > maxT) { maxT = currT }
if (currR > maxR) { maxR = currR }Всё это работает для объектов, начиная со второго (его координаты уже будет с чем сравнивать), а как быть с самым первым? Нельзя же его игнорировать — вдруг он окажется одним из значимых объектов, влияющим на положение границы! Поэтому специально для него зададим пределы самостоятельно, причём они должны заведомо перекрывать возможный диапазон его координат: в таком случае координаты первого объекта автоматически станут начальными границами выделенного блока, подготовив почву для остальных сравнений, которые будут проходить по описанной цепочке. Для этого достаточно указать в качестве крайних значений 10 000 (для левой и нижней границ) и 10 000 — для верхней и правой. Значения приведены в пунктах, с учётом, что наибольший размер у документа формата А0 — менее 4000 точек. Логика рассуждений проиллюстрирована на рис. 1.
Устанавливаем заведомо запредельные начальные границы, чтобы не было никаких ограничений по размерам и положению первого объекта Сколько-сколько?
Получив всю информацию, перейдём к конечной цели — определению коэффициента увеличения просмотра. Ранее мы узнали, что для управления точкой обзора содержимого на экране в Illustrator CS есть объект View. Он, по аналогии с остальными объектами, входит в коллекцию документа Views (activeDocu-ment.Views). Поскольку создаваемый вид будет первым, его индекс «0».
Как вы помните, для отслеживания текущего разрешения экрана мы пошли на хитрость:
v.zoom = 1;
scrW = v.bounds[2] — v.bounds[0];
scrH = v.bounds[1] — v.bounds[3];В предыдущих выпусках мы создали библиотеку наиболее часто используемых ссылок на классы объектов, существующих в Illustrator CS. Продолжим это полезное дело, добавив в скрипт predefined.js (из каталога C:\Documents and Settings\username, где username — имя пользователя) новую строку: v = aD.views[0]
Учитывая, что выражение v.zoom = 1 соответствует масштабу 100%, коэффициенты увеличения получим из отношения видимой части документа к габаритам выделенных объектов — чем меньше объект, тем больше должна быть степень его увеличения.
Переходя непосредственно к определению масштаба, учтём один нюанс, связанный с различиями в пропорциях экрана и габаритного прямоугольника. Допустим, последний вытянут по высоте. Если масштаб задавать жёстко как соотношение ширины, может оказаться, что по горизонтали объекты впишутся в размеры окна, а по вертикали выйдут за его пределы. То же произойдёт и при фиксированном задании масштаба как соотношения высот — в случае, если габаритный прямоугольник вытянут по ширине (см. рис. 2). Следовательно, для универсального решения будем вычислять оба коэффициента увеличения, а использовать наименьший: тогда при любом соотношении сторон объекты не выйдут за границы экрана. Таким образом, масштаб определим как:
Определяем необходимый коэффициент увеличения selW = maxR — maxL;
selH = maxT — maxB;
v.zoom = Math.min( scrW / selW, scrH / selH );где selW и selH — размеры габаритного прямоугольника из выделенных объектов.
А поточнее?
Пока мы предполагали, что объект должен быть вписан точно в размеры экрана. Но на практике это не всегда удобно — ведь вы планируете проводить с ним какие-то дальнейшие действия, например, изменение размеров, не так ли? Вдруг понадобится использовать управляющие, а они уже выйдут за пределы видимости… Следовательно, реальный коэффициент увеличения должен быть чуть меньше. Насколько? Как вариант — отступить от краёв на 10 пикселей; тогда достаточно размеры выделенного блока увеличить на удвоенный отступ (20 пикселей). Но будет ли это всегда удачным? А если попадутся объекты, для которых 10 пикселей соизмеримы с их размерами? Выбранный допуск слишком велик даже для 50-60-пиксельных (около 2 см) элементов (в макетах встречаются достаточно часто), и они будут увеличены недостаточно. Логичнее перейти от абсолютных величин к относительным. Выберем для общего отступа значение 10% (с каждой стороны по 5%). Это даст хорошие результаты при работе даже с крошечными объектами.
v.zoom = Math.min( scrW / (selW * 1.1) , scrH / (selH * 1.1) );
Но если сейчас запустить скрипт, мы получим странную картину: по ширине будет явно «недолёт». Оказывается, пиксели у мониторов на самом деле не совсем квадратные! Их форма зависит от многих факторов. На моём Sony GDM-F500К специальные утилиты показывают, что реальное разрешение экрана 96Ё93 пикселя на дюйм, а не просто 96, как утверждает панель управления Display PropertiesёSettingsёAdvancedёDisplayёDPI settings. Таким образом, в конечном варианте коэффициент увеличения по ширине должен составлять scrW / (selW * 1.1) * 93 / 96 — вроде бы, мелочь, а на глаз заметно! Как показала проверка на нескольких мониторах, такая запись точнее соответствует действительности.
Последний шаг — центрирование области просмотра на экране. Для этого воспользуемся методом centerPoint объекта View, определяющего координаты центра точки обзора у выбранного вида. Ему в качестве параметров укажем
v.centerPoint = Array (maxL + selW / 2, maxT — selH / 2);
Вот, собственно, и всё.
Выводы
Простая, казалось бы, операция FitToZoom не решаема без хитростей, познавательно и выяснение тонкостей экранного разрешения мониторов. Скрипт получился очень компактным, что нисколько не умаляет его практической пользы.
Replace modified
Очередной скрипт в нашей коллекции утилит посвятим замене одних элементов другими с привязкой к размерам. Кроме того, предусмотрим различные способы выравнивания заменяющего объекта относительно заменяемого. Применений скрипта уйма — работа с картами и технической документацией, визитками, при выполнении художественных работ.
А написать скрипт подтолкнул недавний случай: потребовалось оперативно заменить более 300 стилизованных объектов другими.
Анализируй это-2
Какие параметры понадобятся для выполнения таких задач? Во-первых, степень увеличения — заменяющий объект можно масштабировать тремя способами. Чтобы он:
- превышал размеры заменяемого в любом направлении (при условии сохранения соотношения сторон);
- целиком вписывался в заменяемый;
- сохранил размеры (рис. 3).
Три способа замены объектов Удобнее всего работать с опорным объектом, если он располагается на самом верху (ArrangeёBring To Top), поэтому в дальнейших рассуждениях будем исходить из того, что он там уже находится, — следовательно, его индекс в массиве объектов документа «0».
Параметры зададим стандартным методом — через функцию prompt. Начнём с масштабирования. Для первого случая примем обозначение max, для второго — min, для третьего — 1. А как быть с окантовкой? Она может либо тоже масштабироваться, либо оставаться неизменной. Соответственно, следующим будет режим масштабирования окантовки (да/нет).
Способы выравнивания объектов Операция замены объекта другим идентична выравниванию, только исходный объект удаляется. А выравнивание может происходить по любой из границ элементов, поэтому встаёт вопрос об уточнении параметров действия. Логично разделить их на две независимые группы — для горизонтали и вертикали. В каждой границы будем задавать парами (заменяемый/заменяющий объекты), а для удобства используем стандартные обозначения — L (left), R (right), C (hortizontal center) и T (top), B (bottom), E (vertical center). К примеру, выравниванию левой границы заменяющего объекта по центру заменяемого, а вертикально — по их центрам, соответствуют пары значений — CL, EE. (рис. 4, по центру). Иные способы выравнивания приведены там же: сверху — часто используемые (Align Objects), снизу — стык в стык (аналогичные Distribute spacing в Illustrator).
Остался последний вопрос — что делать с опорным объектом? Оставлять или удалять? Ответ на него будет определяться последним задаваемым параметром (Y/N). В качестве набора значений, используемых скриптом по умолчанию, зададим распространённый вариант — размеры сохранять неизменными, окантовку пропорционально масштабировать, выравнивать по центрам (по горизонтали и вертикали), а заменяемый объект удалять.
Задаём окно пользователя:
value = prompt(«Specify parameters: Fit to [min / max / 1], Scale stroke [Y / N],\nAlign horizontally as pair of TOFROM (L, R, C)\nthen vertically as pair (T, B, E)\nDelete reference object? [Y / N]», «1, Y, CC, EE, Y»);
Подсчёты, расчёты…
Следующий этап — разбор строчки, введённой пользователем. В качестве разделителя значений будем использовать запятую с пробелом «, ».
if (value != null) { splitString = value.split( «, « )}
fit = splitString[0];
strokeScale = splitString[1];
hor = splitString[2];
ver = splitString[3];
delRef = splitString[4];Переходим к считыванию крайних точек у заменяемых объектов методом geometricBounds — это позволит унифицировать определение необходимого смещения от опорного элемента до них. Первая пара значений (0, 1) в массиве geometricBounds содержит координаты верхней левой точки (Х, Y), следующая пара — нижней правой (2, 3). Поскольку все объекты имеют индекс больше «0» (это прерогатива опорного), то получаем:
sel = activeDocument.selection;
ref = sel[0];
for (i=1; icL = cur.geometricBounds[0];
cT = cur.geometricBounds[1];
cR = cur.geometricBounds[2];
cB = cur.geometricBounds[3];
cur = sel[i];Далее переходим к определению положений заменяющих объектов согласно заданным значениям. Сначала рассматриваем только горизонталь (см. рис. 4). Перебираем все самые используемые сочетания:if (hor == «LL») { posH = cL }
if (hor == «LR») { posH = cL — ref.width }
if (hor == «RL») { posH = cR }
if (hor == «RR») { posH = cR — ref.width }
if (hor == «CC») { posH = cL + cur.width/2 — ref.width/2 }Для полноты включим выравнивание по границам горизонтального центра — LC, RC, CL, CR, хотя они нужны гораздо реже:
if (hor == «LC») { posH = cL — ref.width / 2 }
if (hor == «CL») { posH = cL + cur.width / 2 }
if (hor == «RC») { posH = cR — ref.width / 2 }
if (hor == «CR») { posH = cL + cur.width / 2 — ref.width }Затем — наиболее часто используемые способы выравнивания по вертикали:
if (ver == «TT») { posV = cT }
if (ver == «TB») { posV = cT + ref.height }
if (ver == «BT») { posV = cB }
if (ver == «BB») { posV = cB + ref.height }
if (ver == «EE») { posV = cT — cur.height / 2 + ref.height / 2 }И для экзотических TE, BE, EB, ET:
if (ver == «TE») { posV = cT + ref.height / 2 }
if (ver == «ET») { posV = cT — cur.height / 2 }
if (ver == «BE») { posV = cB + ref.height / 2 }
if (ver == «EB») { posV = cT — cur.height / 2 + ref.height }Собственно говоря, мы описали не что иное, как операции, выполняемые Illustrator CS при использовании панели TransformёAlign. Осталось разобраться с масштабом. Ему соответствует метод resize, причём, если в качестве параметра задать «1», масштаб будет 100%. Следовательно, для увеличения он должен быть больше 1, для уменьшения — меньше. По ранее рассмотренным причинам, будем определять степень увеличения по горизонтали и отдельно — по вертикали:
ratH = 100 / (ref.width / cur.width);
ratV = 100 / (ref.height / cur.height);Требуемые положение и размеры мы уже можем задавать, поэтому переходим непосредственно к замене.
Разделяй и властвуй
Копию опорного объекта устанавливаем в нужную позицию, а исходный элемент удаляем:
anew = ref.duplicate();
anew.position = Array( posH, posV );
cur.remove()Последний шаг — изменение размеров объекта-заменителя. Логика будет такой: чтобы новый объект полностью поместился в замещаемом (1-й вариант) и толщина его окантовки не менялась, коэффициент увеличения определяется наименьшим значением из соотношений высот объектов и их ширин.
if ((fit == «min») && (strokeScale == «N»)) { (ratH < ratV) ? anew.resize( ratH, ratH ) : anew.resize( ratV, ratV ) }
Запись (а) ? b : c — краткий вариант хорошо известного выражения if (а) then {b} else {c}, который можно применять, если условие и каждый оператор не превышает одной строки.
Если толщину окантовки тоже нужно масштабировать, предыдущая строка примет вид:
if ((fit == «min») && (strokeScale == «Y»)) { (ratH < ratV) ? anew.resize( ratH, ratH, true, true, true, true, ratH ) : anew.resize( ratV, ratV, true, true, true, true, ratV )}
Определение точек привязки для разных способов выравнивания За окантовку отвечает последний параметр. Поскольку он должен идти седьмым, а пропускать промежуточные не допускается, пришлось их перечислить (полное описание параметров метода приведено в справочном руководстве), иначе будет ошибка.
Второй вариант: чтобы размеры нового объекта превышали размеры замещаемого в любом направлении (окантовка остаётся неизменной), масштаб определяется наибольшим значением среди соотношений высоты и ширины объектов:
if ((fit == «max») && (strokeScale == «N»)) { (ratH < ratV) ? anew.resize( ratV, ratV ) : anew.resize( ratH, ratH ) }
Соответственно для адекватного изменения окантовки:
if ((fit == «max») && (strokeScale == «Y»)) { (ratH < ratV) ? anew.resize( ratV, ratV, true, true, true, true, ratV ) : anew.resize( ratH, ratH, true, true, true, true, ratH)}
Последний вариант: если нужно просто поменять объекты, без изменения их размеров, масштаб не меняется:
if (fit==«1») { anew.resize( 100,100 ) } }
Завершающий штрих — если опорный объект после операции замены нужно удалить, выполняем это:
if (delRef==«Y»){ ref.remove() }
Для уверенности в том, что на экране отображается конечный вариант (иногда у Illustrator CS возникают с этим проблемы), выполним его перерисовку:
redraw()
Скрипт готов.
Общие замечания
Дополнительные возможности скрипта:
- замена объектов внутри одной группы (без предварительного разгруппирования);
- замена по типу «блок на блок», т. е. внутреннее содержание выделенного объекта не принимается в расчёт (будь то один объект либо сложная группа, в составе которой могут быть другие) — любой выделенный блок рассматривается как один объект. Соответственно, кроме замены объекта на объект, можно менять группы на группу, объекты на группы и группу на объекты;
- если объектом, не входящим в группу, понадобится заменить некоторые объекты из неё (это можно сделать инструментом Direct Selection), задача будет выполнена.
Универсальный солдат, а не скрипт! А при небольшой доработке (вернее, простом удалении ненужных действий) он может использоваться как более функциональный аналог операций выравнивания в Illustrator, поскольку ему безразлично, в группе объекты или нет.
COLLECT FOR OUTPUT
Последний скрипт текущего выпуска посвятим частой проблеме сбора графики, использованной в макете, в один «мешок» — операции типа Collect For Output из QuarkXPress в Illustrator нет. Мы восполним недостаток, упростив подготовку макета к выводу.
Скрипт полезен во многих случаях: например, при повторном использовании иллюстративного материала макета, поскольку отпадёт необходимость самостоятельно отслеживать связи и путешествовать по каталогам. Альтернатива в виде простого копирования через буфер обмена чревата негативными последствиями — ведь исходные размеры изображений наверняка изменялись, а многократное их масштабирование может привести к выходу из допустимого диапазона увеличения для растровых картинок.
Вторая причина — нежелание создавать один огромный файл (с внедрёнными изображениями). В случае же сохранения связей на вас лежит забота о сборе всех источников с тем, чтобы потом передать их в репроцентр. Опять маячит малопривлекательная перспектива просмотра в макете свойств каждого изображения с последующим поиском файлов локально или по сети. Скрипт избавляет от этой монотонной работы и одновременно страхует от ошибок и пропусков. Если заинтересовались — к делу.
Первый шаг — подключаем ссылки на объекты, а для вывода в конце работы количества скопированных изображений делаем для них счетчик.
//@include «~/predefined.js»;
linked = 0;Для поддержания порядка на диске все копии будем создавать в подкаталоге «4output», расположив его в том же каталоге, где хранится сам макет. Для работы с файловой системой (на Windows и Mac) в Illustrator CS есть поддержка объектов Folder, File и методов Path, FullName и Name. Отличия между ними в том, что первый определяет только путь к файлу (без имени), второй — полный путь (с именем файла), последний — только название файла. Все выдают «голый» результат (без ограничивающих символов «/», необходимых для корректной связки составляющих частей сложного адреса). Соответственно для указания в качестве пути для нашей папки-назначения запишем:
targetFolderName = «4output»;
imagesFolder = aD.path + «/» + targetFolderName + «/»;Поскольку Folder и File — не «родные» объекты Illustrator CS, приёмы работы с ними отличаются от нам известных. Сначала явно объявляется объект необходимого типа (как в JavaScript), а затем описываются действия над ними. Создаём новую папку с заданным именем.
folder = new Folder(imagesFolder);
folder.create();Проверяем у всех растровых объектов по очереди «прописку»: внедрены они в файл (embedded) или только с ним связаны.
for (i=0; iif (rI[i].embedded == false) {Если связаны, считываем путь к файлу с изображением на диске и вместо него подставляем новый путь:source = rI[i].file.fullName;
source = new File(source);
target = imagesFolder + «/»+ rI[i].file.name;
file = new File(target);После чего копируем файл в новое место, ссылку в макете меняем на новый адрес и учитываем его как перемещённый:
source.copy(target);
rI[i].file = file;
linked++;Все изображения скопированы в указанную папку, что нам и требовалось.
Проверяем тонкие места
Предыдущие скрипты мы тестировали на предмет работы в различных внештатных ситуациях — этот скрипт не станет исключением. Во-первых, некоторые использованные изображения могли быть впоследствии перемещены или переименованы. Тогда есть смысл оставлять их выделенными и сигнализировать о том, что данная проблема существует:
if (source.exists == false) {
rI[i].selected = true;
removed = true; }Во-вторых, некоторые изображения могут быть внедрёнными. Нам не остаётся ничего другого, как поступить так же:
} else {
rI[i].selected = true;
emb = true; } }В самом конце выдаём необходимые предупреждения, а заодно — статистику по обработанным файлам:
if (emb == true) { alert («Selected files are embedded so they weren't copied!»);}
if (removed == true) {alert («Selected files out of theirs original locations!»); }
alert ( linked + « linked files were copied into '« + targetFolderName + «' subfolder of the document folder»);Анализируя скрипт, отметим некорректность его работы, если в макете одновременно присутствуют внедрённые и связанные изображения, но с потерянными связями — те и другие будут выделены, что затруднит их дальнейший разбор. Но имейте в виду: скрипт выделяет только проблемные места, которые в любом случае требуют от дизайнера дополнительного внимания, а излишнее усложнение скрипта не стоит такого незначительного повышения функциональности. К тому же, трудно представить ситуацию, когда проблемными окажутся столько изображений, что это вызовет сложности при работе с ними. В крайнем случае можно добавить перед копированием файлов проверку: source.fullName != target, которая будет препятствовать перезаписи уже существующих в новой папке изображений в случае многократного запуска скрипта при пошаговом поиске опасных мест.
Резюме
Мы научились работать с объектами View, File, Folder (последние пригодятся чуть позже, когда мы будем создавать просмотровщик содержимого папок в векторных форматах с возможностью автоматической его распечатки) и получили 3 скрипта, имеющих несомненную практическую пользу. Первым двум желательно назначить клавиатурные сокращения — в таком случае они будут у вас всегда под рукой.
Об авторе: Михаил Борисов (mikeb@ukrsat.com), пишет для Publish полезные советы и обзоры ПО.
С вопросом сокращения объёма файла непосредственно связан ещё один скрипт. Он касается оптимизации размера документа, в который изображения по каким-то причинам оказались внедрёнными. Ручная «линковка» займёт определённое время, к тому же нужно будет заново указывать параметры трансформации, если она проводилась. Скрипту Deembed в данном случае достаточно изменить единственный параметр изображения, и вся работа будет выполнена. Вот как это делается:
//@include «~/predefined.js»
var deembedded = 0;
for (i=0; iif (rI[i].embedded == true) {
rI[i].embedded = false;
deembedded++;
} }
alert («Deembedded «+ deembedded + « pictures»)