Сниппет позволяет выводить галерею в стиле Вконтакте или Яндекс.Картинок. Вот так, например:

Расскажу, как я этого добился и немного прокомментирую код сниппета.
Алгоритм ресайза изображений
Картинки по условиям обрезать нельзя, но они все равно должны быть одинаковыми по высоте и помещаться ровно в заданную ширину. Сразу скажу, что весь секрет в том, чтобы подобрать такую высоту картинок, чтобы при ресайзе до этой высоты всех картинок в строке их общая ширина была равна конкретному значению.
Давайте посмотрим, как высчитывается нужная высота картинок.
Сначала нужно узнать, сколько картинок будет в каждой строчке. Это количество мы узнаем от пользователя, который при вызове сниппета указывает параметр &lineLimit.
Дальше мы ресайзим все картинки в строке по наименьшей высоте, чтобы выровнять их. Например так:

После этого находим суммарную ширину получившихся картинок в строке:

Width = W_1 + W_2 + W_3
И находим нужную высоту умножением минимальной высоты картинок в строке на коэффициент ресайза, который равен:
&lineWidth / Widthгде &lineWidth — это требуемая ширина строки (которую задает пользователь при вызове сниппета), а Width — найденная в предыдущем шаге общая ширина.
Height = Height_Min * &lineWidth / Width
Реализация алгоритма в коде
Получаем картинки, разбитые на линии:
$i = 0;
$Lines = array(); // каждый элемент этого массив - строка картинок
$isItems = true; // проверяем, не кончились ли картинки
while ($isItems) {
$scriptProperties['outputSeparator'] = ',';
$scriptProperties['limit'] = $lineLimit;
$scriptProperties['offset'] = $i;
// сколько всего картинок будет после текущей итерации
$subTotal = $scriptProperties['offset'] + $lineLimit;
// если предсказывается превышение лимита
if ($limit && $subTotal > $limit) {
/* изменяем лимит — например, при выводе пяти картинок по 3 в строке
в последней итерации лимит должен быть равен 2, а не 3) */
$scriptProperties['limit'] = $limit - $scriptProperties['offset'];
}
// получаем список картинок для этой строки
$result = $modx->runSnippet($snippet, $scriptProperties);
// если картинки кончились, выход из цикла
if (!$result) break;
// превращаем список в JSON-массив
$Lines[] = '{' . $result . '}';
// проверяем, все ли картинки вывелись
$i = $i + $lineLimit;
if ($i >= $limit) $isItems = false;
}И обрабатываем каждую строку с помощью нашего алгоритма:
foreach ($Lines as $line) {
// получаем обычный массив картинок
$line = $modx->fromJSON($line);
$images = $w = $h = array();
// вычисляем размеры каждой картинки
foreach ($line as $id => $img) {
// убираем слеш в начале пути
if (substr($img,0,1) == '/') $img = substr($img,1);
// если указано, что нужно обрезать лишний фон, выполняем
if ($crop) {
// используем для этого Imagik - в MODX есть по умолчанию
$im = new Imagick($img);
// обрезаем фон
$im->trimImage(0);
// готовим новое имя картинки, чтобы сохранить ее
$path_info = pathinfo($img);
$cropedFile = $path_info['dirname'].'/croped-'.$lineWidth.'/';
if (!file_exists($cropedFile)) mkdir($cropedFile);
$cropedFile .= $path_info['basename'];
// и, собственно, сохраняем
$im->writeImage($cropedFile);
$img = $cropedFile;
}
// узнаем высоту и ширину картинки
$size = getimagesize($img);
$w[] = $size[0];
$h[] = $size[1];
$images[$id] = $img;
}
/* ресайзить картинки по наименьшей высоте не будем — вдруг, потом
придется их обратно увеличивать? Просто высчитываем,
какой была бы ширина отресайзенных картинок */
foreach ($w as $k => $w_old) {
$w[$k] = floor($w_old * min($h) / $h[$k]);
}
// высчитываем требуемую высоту
$lineHeight = floor(min($h) * $lineWidth / array_sum($w));
// и ресайзим картинки по этой высоте
foreach ($images as $id => $image) {
$ph = $tvPrefix.$processImage;
$im = new Imagick($image);
$im->resizeImage(0,$lineHeight,0,1);
// новое имя картинки, уже отресайзеной
$path_info = pathinfo($image);
$image = $path_info['dirname'].'/h-'.$lineHeight.'/';
if (!file_exists($image)) mkdir($image);
$image .= $path_info['basename'];
// сохраняем картинку
$im->writeImage($image);
// и показываем пользователю
$output .= $modx->getChunk($template,
array($ph => $image
, 'id' => $id
, 'album' => $scriptProperties['album']))."\n";
}
}
return $output;Результат

И еще совет напоследок — устанавливайте значение параметра &lineWidth на 10-15 пикселей меньше контейнера, чтобы между изображениями было расстояние и картинки не «слипались». G+
UPD. Pashkevich Aleksandr переработал компонент, выложил его в репозиторий MODX. Описание.
Объектная
Для ms2Gallery не появлялось готового решения?
А вдруг?)))
Т.е., ну создает свои превьюшки ms2Gallery и пусть создает, можно в источнике указать минимальное количество ее собственных превьюшек.
... $photosObj = $modx->vk->api('photos.get', array( 'album_id' => $album, 'owner_id' => $owner, 'count' => $limit, 'photo_sizes' => '1'),$https)[response]; if (!empty($photosObj) && count($photosObj) > 0) { $photos = array(); foreach ($photosObj[items] as $item) // тут просто собираю нужные мне поля { $photos[] = array( 'caption' => $item[text], //подпись 'thumb' => $item[sizes][$thumbSize][src], //картинка-превью 'thumbHeight' => $item[sizes][$thumbSize][height], //высота превью 'thumbWidth' => $item[sizes][$thumbSize][width], //ширина превью 'photo' => $item[sizes][$bigSize][src], //картинка-оригинал 'photoHeight' => $item[sizes][$bigSize][height], //высота оригинала 'photoWidth' => $item[sizes][$bigSize][width]); //ширина оригинала } $Lines = array_chunk($photos, $lineLimit); //делю на строки ...Или это лучше делать на JavaScript?