Перейти к основному содержимому

Миниатюры изображений

Для изображений Pimcore предлагает расширенный сервис создания миниатюр, который также называется "конвейер изображений". Он позволяет вам преобразовывать изображения неограниченным количеством шагов для получения ожидаемого результата. Вы можете настроить их в разделе Settings > Thumbnails.

С помощью этого сервиса каждое изображение, сохраненное в качестве ассета, может быть преобразовано. Pimcore не поддерживает изменение изображений, которые не хранятся как ассеты внутри Pimcore.

ВАЖНО
Для достижения наилучших результатов используйте расширение Imagick PECL, GDlib - это просто запасной вариант с ограниченной функциональностью (только PNG, JPG, GIF) и меньшим качеством! Если доступно расширение Imagick, оно будет использоваться по умолчанию, в противном случае возвращайтесь к GD. С помощью ImageMagick Pimcore может поддерживать сотни форматов, включая: AI, EPS, TIFF, PNG, JPG, GIF, PSD и т.д. Не все форматы доступны в готовом виде. Чтобы расширить список смотрите.

Чтобы воспользоваться сервисом создания миниатюр в Pimcore, сначала необходимо создать конвейер преобразования. Для этого откройте Settings > Thumbnails и нажмите Add Thumbnail, чтобы создать новую конфигурацию. Название, описание, формат и качество полей должны быть понятны сами по себе, теперь самое интересное - это преобразования. Нажмите на +, чтобы добавить новое преобразование, чтобы оно выглядело, например, так:

Thumbnails

Важно: Преобразования выполняются в порядке сверху вниз. Это важно, например, в приведенной выше конфигурации. Если вы сначала закруглите углы, это будет выполнено на исходном изображении, а затем размер изображения будет изменен, поэтому размер закругленных углов также будет изменен, что не предусмотрено.

Чтобы получить миниатюру из ассета, просто вызовите $asset->getThumbnail("thumbnail-name") для объекта asset, которая вернет объект \Pimcore\Model\Asset\Image\\Thumbnail. Метод __toString() объекта thumbnail возвращает путь к файлу миниатюр, например: /Car%20Images/ac%20cars/68/image-thumb__68__content/automotive-car-classic-149813.jpg

Важно: Функция getThumbnail() не генерирует саму миниатюру. Она просто возвращает путь, по которому будет сохранен файл миниатюр. Если вы хотите сгенерировать миниатюру напрямую, посмотрите на [Отложенный рендеринг миниатюр](#Отложенный рендеринг миниатюр)

Затем этот путь можно напрямую использовать для отображения изображения в теге <img /> или <picture>. Например:

$image = Asset::getById(1234);  

// получить путь к миниатюре, например `/foo/bar/362/image-thumb__362__content/foo.webp
$pathToThumbnail = $image->getThumbnail("myThumbnailName");

// предпочтительная альтернатива - позволить Pimcore создать тег всего изображения целиком.
// включая альтернативы с высоким разрешением (srcset) или медиазапросы, если они настроены
$htmlCode = $image->getThumbnail("myThumbnail")->getHtml();

То же самое в Twig:

{% set image = pimcore_asset(1234) %}  

{# получить путь к миниатюре, например `/foo/bar/362/image-thumb__362__content/foo.webp #}
<img src="{{ image.thumbnail('myThumbnailName') }}">

{# предпочтительная альтернатива - позволить Pimcore создать тег всего изображения целиком. #}
{# включая альтернативы с высоким разрешением (srcset) или медиазапросы, если они настроены #}
{{ image.thumbnail('myThumbnailName').html|raw }}

Объяснение преобразований

ПреобразованиеОписаниеКонфигурацияРезультат
ORIGINAL IMAGEЭто изображение, которое используется в следующих преобразованияхНЕТ ;-)Образец оригинала
RESIZEИзображение точно соответствует заданным размерам без соблюдения соотношения.Изменение размера конфигурацииИзменение размера образца
SCALE BY HEIGHTИзображение масштабируется в соответствии с заданной высотой, ширина варьируется в зависимости от исходного соотношения изображения (портретное, альбомное).Высота конфигурацииВысота образца
SCALE BY WIDTHИзображение масштабируется в соответствии с заданной шириной, высота изменяется в зависимости от исходного соотношения изображения (портретное, альбомное).Ширина конфигурацииШирина образца
CONTAINИзображение масштабируется либо до заданной высоты, либо до ширины, в зависимости от соотношения размеров исходного изображения. Это означает, что изображение масштабируется так, чтобы оно помещалось в "виртуальную" рамку с размерами, указанными в конфигурации.Config ContainSample Contain
CROPВырезает рамку изображения, начиная с заданных координат X,Y и используя ширину и высоту.Настройка обрезкиПример обрезки
COVERРазмер изображения изменяется таким образом, чтобы оно полностью соответствовало заданным размерам. Затем накладывающиеся друг на друга фрагменты обрезаются в зависимости от заданного положения или на основе фокусной точки, установленной на исходном изображении. Это полезно, если вам нужен фиксированный размер миниатюры, но исходные изображения имеют разное соотношение сторон.Конфигурация обложкиОбразец обложки
FRAMEПреобразование такое же, как и CONTAIN, разница в том, что изображение приобретает точно заданные размеры, добавляя прозрачные границы слева / справа или сверху / снизу.Конфигурация рамки / Образец рамки
ROTATEПоворачивает изображение на заданный угол. По умолчанию фон прозрачный.Поворот конфигурацииПример поворота
BACKGROUND COLORЦвет фона особенно полезен, если у вас есть прозрачный формат PNG в качестве исходных данных или если вы используете рамку или поворотные преобразования, при которых вы получаете прозрачные пленки. Это позволяет вам придать прозрачным пленкам цвет и дает вам возможность использовать их для примеров JPEG, которые не поддерживают прозрачность.Конфигурация фонаОбразец фона
ROUNDED CORNERSОкругляет углы до заданной ширины / высоты.Конфигурация углаОбразец угла

Чтобы увидеть миниатюры в действии, также ознакомьтесь с нашей живой демонстрацией.

Создание HTML-кода для миниатюр

Pimcore предлагает метод getHTML(array $options), позволяющий получить готовый к использованию тег <picture> для вашей миниатюры. Когда элемент <picture> не нужен или нежелателен, можно использовать элемент <img />, вызвав вместо него getImageTag(array $options).

Вы можете настроить сгенерированную разметку с помощью следующих параметров:

ИмяТипОписание
disableWidthHeightAttributesboolАтрибуты ширины и высоты автоматически устанавливаются Pimcore, чтобы избежать этого, установите этот параметр (например. в true => проверка isset)
disableAutoTitleboolУстановите значение true, чтобы отключить автоматически сгенерированный атрибут title (содержащий название и авторские права на исходное изображение)
disableAutoAltboolУстановите значение true, чтобы отключить автоматически сгенерированный атрибут alt
disableAutoCopyrightboolУстановите значение true, чтобы отключить автоматически добавляемую информацию об авторских правах (атрибут alt и title)
disableAutoCopyrightboolУстановите значение true, чтобы отключить автоматически добавляемую информацию об авторских правах (атрибут alt и title)
pictureAttributesarrayМассив пользовательских атрибутов типа ключ-значение, которые должны быть применены к сгенерированному тегу <картинка>
imgAttributesarrayМассив пользовательских атрибутов типа ключ-значение, которые должны быть применены к сгенерированному тегу <img>
lowQualityPlaceholderboolПомещает небольшое изображение-заполнитель в формате SVG/JPEG в "src" (data-uri), реальный путь к изображению помещается в data-src и data-srcset.
pictureCallbackcallablecallback-функция для изменения атрибутов для сгенерированного тега <picture>. Передан 1 аргумент, массив атрибутов.
sourceCallbackcallablecallback-функция для изменения атрибутов для любого из сгенерированных тегов <source>. Передан 1 аргумент, массив атрибутов.
imgCallbackcallablecallback-функция для изменения атрибутов для сгенерированного тега <img>. Передан 1 аргумент, массив атрибутов.
disableImgTagboolУстановите значение true, чтобы не включать резервный тег <img> в сгенерированный тег <picture>.
useDataSrcboolУстановитен значение true, чтобы использовать атрибуты data-src(set) вместо src(set).
useFrontendPathboolУстановите значение true, чтобы использовать полный URL (включая frontend_prefix).

Информация: Функция автоматического изменения Alt попытается автоматически вернуться к любому доступному значению alt, также проверив записи метаданных (с именем alt, defaultalt). В конечном счете, он будет использовать title в качестве значения alt, если ранее ничего из вышеперечисленного найдено не было. Также возможно определить альтернативные метаданные, которые будут использоваться в качестве значений alt, copyright, title (например, путем определения pimcore.assets.metadata.alt в конфигурации), которые использовались бы, если бы не были переданы встроенные параметры.

  
## Примеры использования

```twig
/* Использование непосредственно на объекте ассета */
{{ pimcore_asset_by_path('/path/to/image.jpg').thumbnail('myThumbnail').html|raw }}

/* ... с некоторыми дополнительными опциями */
{{ pimcore_asset_by_path('/path/to/image.jpg').thumbnail('myThumbnail').html({
pictureAttributes: {
data-test: "my value"
},
disableImgTag: true
})|raw }}

/* Использование с тегом image в документах */
<div>
<p>
{{ pimcore_image('myImage', {'thumbnail': 'myThumbnail'}) }}
</p>
</div>

/* Использование без предварительно настроенной миниатюры */
{{ pimcore_image('myImage', {
'thumbnail': {
'width': 500,
'aspectratio': true,
'interlace': true,
'quality': 85,
'format': 'png'
}
}) }}

/* Использование из поля объекта */
/* где "myThumbnail" это название конфигурации миниатюр в разделе settings -> thumbnails */
{% if myObject.myImage %}
{{ myObject.myImage.thumbnail('myThumbnail').html|raw }}
{% endif %}


/*Использование из поля объекта с динамической конфигурацией */
<img src="{{ myObject.myImage.thumbnail({'width': 220, 'format': 'jpeg'}) }}" />


/* Использование непосредственно на объекте ассета с использованием динамической конфигурации */
{{ pimcore_asset_by_path('/path/to/image.jpg').thumbnail({'width': 500, 'format': 'png'}).html|raw}}

Дополнительные примеры

Pimcore возвращает объект \Pimcore\Model\Asset\Image\Thumbnail при вызове $asset->getThumbnail("thumb-name"), что обеспечивает еще большую гибкость при работе с миниатюрами.

$thumbnail = $asset->getThumbnail("myThumbnail");  

// получить окончательные размеры миниатюры (особенно полезно при работе с динамическими конфигурациями)
$width = $thumbnail->getWidth();
$height = $thumbnail->getHeight();

// получить html-тег "<picture>" для миниатюры, включая пользовательский класс, содержащий тег "<img>":
echo $thumbnail->getHtml(['imgAttributes' => ["class" => "custom-class"]]);

// получить путь к миниатюре
$path = $thumbnail->getPath();

// получить путь и отключить отложенные миниатюры
$path = $thumbnail->getPath(["deferredAllowed" => false]);
// возможные опции: ["deferredAllowed" => true, "cacheBuster" => false, "frontend" => false]

// получение полного URL-адреса миниатюры (включая frontend_prefix) - также работает в консольных командах
$path = $thumbnail->getFrontendPath();
//или
$path = $this->getPath(['deferredAllowed' => false, 'frontend' => true]);

// Asset\Image\Thumbnail реализует __toString(), так что вы все равно можете напечатать путь с помощью
echo $thumbnail; // prints something like /Car%20Images/....png

// примеры обратных вызовов и т.д. для сгенерированного тега <picture>
$thumbnail->getHtml([
'useDataSrc' => true,
'pictureAttributes' => [
'data-bar' => uniqid(),
],
'imgAttributes' => [
'data-foo' => uniqid(),
],
'imgCallback' => function ($attributes) {
// изменение атрибутов тега <img>
$attributes['data-foo'] = 'new value';
return $attributes;
},
'sourceCallback' => function ($attributes) {
// изменение атрибутов тега <source>
$attributes['data-custom-source-attr'] = uniqid();
return $attributes;
},
'pictureCallback' => function ($attributes) {
// изменение атрибутов тега <source>
$attributes['data-custom-picture-attr'] = uniqid();
return $attributes;
},
'disableImgTag' => true,
'lowQualityPlaceholder' => true,
]);
// получить экземпляр миниатюры в определенном формате файла
$webpThumbnail = $thumbnail->getAsFormat('webp');
$webpThumbnail->getHtml();

Больше примеров

  
/* добавление пользовательских html-атрибутов к сгенерированному тегу <img> или <picture> с использованием динамической миниатюры */
{{ image.thumbnail({
'width': 180,
'height': 180,
'cover': true,
}).html({
'imgAttributes': {
'class': 'thumbnail-class',
},
'data-my-name': 'my value',
'attributes': {
'non-standard': 'HTML attributes',
'another': 'one'
}
})|raw }}

/* то же самое с определением миниатюры */
{{ image.thumbnail('exampleScaleWidth').html({
'pictureAttributes': {
'class': 'thumbnail-class',
},
'data-my-name': 'my value',
})|raw }}

/* отключить автоматически добавляемые атрибуты ширины и высоты */
{{ image.thumbnail('exampleScaleWidth').html({}, ['width', 'height'])|raw }}

/* добавить alt текст */
{{ image.thumbnail('exampleScaleWidth').html({'alt': 'top priority alt text'})|raw }}
/* ИЛИ */
{{ image.thumbnail('exampleScaleWidth').html({'defaultalt': 'default alt, if not set in image'})|raw }}


/* Вывести только элемент <img> без <picture> и <source> вокруг него */
{{ image.thumbnail('exampleScaleWidth').imageTag({'alt': 'top priority alt text'}) }}

Кроме того, существуют некоторые специальные параметры для настройки сгенерированного HTML-кода изображения.

Отложенная загрузка

По умолчанию изображения загружаются с задержкой. Это можно изменить, установив значение "eager" в imgAttribute:

  
{{ image.thumbnail('example').html({
'imgAttributes': {
'loading': 'eager',
}
})|raw }}



Использование цветовых профилей ICC для CMYK -> RGB

Pimcore поддерживает цветовые профили ICC для получения лучших результатов при преобразовании изображений CMYK (без встроенного цветового профиля) в RGB.

Из-за проблем с лицензированием Pimcore не включает цветовые профили (файлы *.icc) в пакет загрузки, но вы можете скачать их бесплатно здесь: Adobe ICC Profiles или здесь: ICC (color.org).

После загрузки профилей поместите их в папку вашего проекта или в любое другое место на вашем сервере (например, /usr/share/color/icc). Затем укажите путь в файле конфигурации Pimcore:

pimcore:  
assets:
# Абсолютный путь к профилю ICC RGB по умолчанию (если не указан встроенный профиль)
icc_rgb_profile: null

# Абсолютный путь к профилю ICC CMYK по умолчанию (если не указан встроенный профиль)
icc_cmyk_profile: null

Динамическая генерация по запросу

Pimcore автоматически генерирует миниатюру если запрошено, но она не существует в файловой системе и вызывается напрямую через путь к файлу (не используя ни один из методов getThumbnail()). Например: Вызов https://example.com/examples/panama/6644/image-thumb__6644__contentimages/img_0037.jpeg (/examples/panama/ - это путь к исходному ассету, 6644 - идентификатор исходного ассета, contentimages - название конфигурации миниатюр, img_0037.jpeg - имя файла исходного ассета) непосредственно в вашем браузере. Теперь Pimcore проверяет, существует ли ассет с идентификатором 6644 и миниатюрой с ключом contentimages, если да, то миниатюра генерируется "на лету" и доставляется клиенту. При повторном запросе изображений изображение напрямую обрабатывается веб-сервером (Apache, Nginx), поскольку файл уже существует (точно так же, как это работает с методами getThumbnail()).

Структура пути идентична структуре, сгенерированной методами getThumbnail(), поэтому не имеет значения, сгенерирована ли миниатюра с помощью getThumbnail() (внутри PHP-процесса) или на лету (в отдельном процессе).

Конечно, это работает только с предопределенными (именованными) конфигурациями миниатюр, а не с динамическими конфигурациями.

Отложенный рендеринг миниатюр

По соображениям производительности Pimcore не генерирует уменьшенное изображение напрямую при вызове функции getThumbnail() для ресурса, вместо этого он генерирует их, когда они действительно необходимы (по запросу).

Но иногда необходимо, чтобы само изображение было уже сгенерировано, в этом случае вы можете передать второй параметр в getThumbnail(), чтобы ускорить обработку изображения.

$asset = Asset\Image::getById(123);  
$asset->getThumbnail("myConfig", false); // установите для 2-го параметра значение false

Обработка также принудительно выполняется при вызове метода getPathReference() или getPath(["deferredAllowed" => false]) для возвращаемого объекта thumbnail:

$asset->getThumbnail("myConfig")->getPathReference();  
// или
$asset->getThumbnail("myConfig")->getPath(['deferredAllowed' => false]);

Поддержка высокого разрешения

Это специальная функциональность, позволяющая встраивать изображения с высоким разрешением (ppi/dpi). Следующее необходимо только в особых случаях использования, таких как Web-to-Print, в обычных веб-приложениях Pimcore автоматически добавляет атрибут srcset к тегам <img> и <picture>, поэтому ручная работа не требуется.

Коэффициент масштабирования с высоким разрешением ограничен значением 5.0, например, @5x. Поддерживаются значения с плавающей точкой. Если вам нужно увеличить масштаб изображения, вы можете использовать параметр max_scaling_factor в конфигурации.

  pimcore:  
assets:
thumbnails:
max_scaling_factor: 6.0

Использование в конфигурации миниатюр:

высокое разрешение Приведенная выше конфигурация сгенерирует миниатюру шириной 500 пикселей.

При использовании этой конфигурации в сочетании с редактируемым элементом Image используя следующий код

{{ pimcore_image('myImage', {'thumbnail': 'contentimages'}) }}  

это генерирует следующий код:

<img src="/Car%20Images/ac%20cars/68/image-thumb__68__contentimages/automotive-car-classic-149813@2x.png" width="250" height="190" />  

Также возможно динамическое добавление изображений с высоким разрешением:

{{ pimcore_image('myImage', {thumbnail: {  
width: 250,
contain: true,
highResolution: 2
}}) }}

Это позволит создать изображение width = 500px

Сочетание "Динамической генерации по запросу" с изображениями высокого разрешения

Это особенно полезно в том случае, если вы хотите отображать миниатюры в зависимости от разрешения экрана устройства или в сочетании с документами Web2Print (предварительный просмотр в браузере с обычным размером, увеличенный в три раза для вывода в формате PDF). Pimcore также использует эту функциональность для обеспечения автоматически добавляемой поддержки высокого разрешения в тегах <img> и <picture>. И снова, эта функция полезна только в некоторых крайних случаях.

Пример
{{ image.thumbnail('testThumbnailDefinitionName').path }}  

это генерирует следующий код:

/Car%20Images/ac%20cars/68/image-thumb__68__testThumbnailDefinitionName/automotive-car-classic-149813.jpg  

Чтобы получить миниатюру в высоком разрешении, вы можете просто добавить @2x перед расширением файла:

/Car%20Images/ac%20cars/68/image-thumb__68__content/automotive-car-classic-149813@2x.png  
/Car%20Images/ac%20cars/68/image-thumb__68__content/automotive-car-classic-149813@5x.png

Использование float также возможно:

/Car%20Images/ac%20cars/68/image-thumb__68__content/automotive-car-classic-149813@3.2x.png  

Затем Pimcore соответствующим образом динамически сгенерирует миниатюры.

Медиа-запросы (media queries) в конфигурации миниатюр

Если вы используете медиа-запросы в своей конфигурации миниатюр, Pimcore автоматически генерирует тег <picture> при вызове $asset->getThumbnail("example")->getHtml(). Но в некоторых случаях необходимо получить отдельные миниатюры для определенных медиа-запросов из объекта thumbnail, что описано в примерах ниже.

$a = Asset::getById(71);  

// отобразить список всех доступных media в миниатюре "galleryCarousel"
p_r(array_keys(Asset\Image\Thumbnail\Config::getByName("galleryCarousel")->getMedias()));

// получить элемент <picture> для "galleryCarousel" => поведение по умолчанию
$a->getThumbnail("galleryCarousel")->getHtml();

// получить путь к миниатюре для медиа-запроса min-width: 940px
$a->getThumbnail("galleryCarousel")->getMedia("(min-width: 940px)");

// получить тег <img> для медиа-запроса min-width: 320px, включая @srcset 2x
$a->getThumbnail("galleryCarousel")->getMedia("(min-width: 320px)")->getHtml();

// получить путь к 2-кратной миниатюре для min-width: 320px
$a->getThumbnail("galleryCarousel")->getMedia("(min-width: 320px)", 2);

Фокусная точка (Focal Point)

Pimcore поддерживает фокусные точки на изображениях, которые учитываются при автоматической обрезке изображений. На данный момент это имеет смысл, только если используется функция преобразования COVER. Если на исходном изображении установлена фокусная точка, она автоматически учитывается, и миниатюра соответствующим образом обрезается, чтобы изображение находилось в фокусе.

Определение фокусной точки для ассетов изображений

Пункт контекстного меню &quot;Фокусная точка&quot; для редактируемого элемента image документа

Преобразование миниатюр изображений с учетом фокусной точки

Поддержка обрезки

Изображения со встроенным контуром обрезки (8BIM / метаданные профиля Adobe) автоматически обрезаются при создании их миниатюр.

Если вы не хотите использовать автоматическое обрезание миниатюр, вы можете отключить поддержку, добавив следующий параметр настройки:

pimcore:  
assets:
image:
thumbnails:
clip_auto_support: false

Примечание по использованию WebP в Imagick с использованием делегатов

Пожалуйста, убедитесь, что ваше определение делегата для кодировки WebP включает флаг -q, в противном случае параметр качества для миниатюр не будет учитываться, и cwebp использует значение по умолчанию 75.

Рабочий пример делегата WebP-кодирования (определенный в /etc/ImageMagick-6/delegates.xml):

<delegate decode="png" encode="webp" command="&quot;cwebp&quot; -quiet -q %Q &quot;%i&quot; -o &quot;%o&quot;"/>  

Скачивание миниатюр ассетов

Помимо встраивания миниатюр на страницы CMS и распространения их по другим каналам, пользователи серверной части могут скачивать миниатюру ассета. Чтобы сделать миниатюру доступной для загрузки, установите флажок "List as option in download section on image detail view" в расширенных настройках миниатюр изображений. Все миниатюры, для которых включена эта опция, отображаются в раскрывающемся списке "List as option in download section on image detail view" при детальном просмотре ассета. Чтобы скачать миниатюру ассета, выберите ее из списка и нажмите кнопку "Download".

Настройка автоматического (веб-оптимизированного) формата

Для большинства веб-приложений рекомендуется использовать автоматическую настройку, которая выполняет несколько функций:

  • автоматический выбирает целевой формат изображения (jpeg, png) на основе характеристик изображения (таких как альфа-канал).
  • предоставляет несколько дополнительных оптимизированных графических форматов (webp, avoid) с использованием прогрессивного улучшения (в теге <picture)
  • запускает оптимизаторы изображений (такие как jpegoptim и pngout) для сгенерированных изображений с использованием асинхронной очереди.

Даже если этот параметр выполняет довольно много функций автоматически, все равно требуется задать качество в конфигурации миниатюры. Это качество будет использоваться для jpeg и png, а если не настроено иначе, то и для webp. Если Imagick поддерживает avif, качество, заданное в конфигурации миниатюр, не будет использоваться, а будет использоваться фиксированное значение.
Можно настроить используемые альтернативные форматы изображений и их свойства, используя следующую конфигурацию:

pimcore:  
assets:
image:
thumbnails:
auto_formats:
# качество, используемое Imagick, установите null, если следует использовать значение качества из конфигурации
# следующая конфигурация используется Pimcore по умолчанию
# порядок форматов используется для определения приоритета <source> в теге <picture>
avif:
quality: 15
webp:
quality: null
enabled: true

Конфигурация для отключения всех автоформатов

pimcore:  
assets:
image:
thumbnails:
auto_formats: null

Ручное указание используемого адаптера для обработки изображений (Imagick или GD).

С помощью Pimcore можно вручную указать используемый адаптер для обработки изображений. Вы можете выбрать Imagick или GD, значение по умолчанию определяется автоматически в зависимости от наличия расширения PECL imagick. Также возможно реализовать свой собственный адаптер, реализовав Pimcore\Image\AdapterInterface.

Чтобы указать используемый графический адаптер, пожалуйста, воспользуйтесь следующей конфигурацией сервиса:

services:   
Pimcore\Image\AdapterInterface:
alias: Pimcore\Image\Adapter\GD
public: true

Пожалуйста, имейте в виду, что сервис адаптера должен быть общедоступным.


Вы можете предложить улучшение документации или задать вопрос в комментариях.
Если вам нужна полноценная консультация — вы можете заказать её на нашем сайте.