@Snewer

Как подобрать размеры изображений, что бы получить прямоугольник?

Здравствуйте!

Имеется массив с данными о изображениях:
[
    [
        'url' => 'ссылка на изображение',
        'width' => 'ширина изображения',
        'height' => 'высота изображения',
        ...
    ]
]


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

Есть ли какие-либо алгоритмы? Идеи?
Спасибо!
  • Вопрос задан
  • 405 просмотров
Решения вопроса 2
xmoonlight
@xmoonlight
https://sitecoder.blogspot.com
1. Делите Ваш будущий прямоугольник на сетку областей 50x50px, например.
2. Определяете отношения сторон у каждого изображения и вписываете в сегменты сетки (определяете через кратность).
3. После получения "фигурок" - Вам их нужно расположить друг за другом.
4. Самый простой способ заполнения с максимальной площадью - это в высоту 6 блоков и кирпичная кладка: остался зазор - ищем подходящий блок по высоте блок, не нашли подходящий блок - ставим другой вместо предыдущего и снова ищем.
Ответ написан
@GreatRash
А как это сделано вконтакте? Скрин можете показать?
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
usdglander
@usdglander Куратор тега PHP
Yipee-ki-yay
Тут скорее всего без обрезки можно обойтись только в исключительных случаях! Проще всего приводить все изображения к одному формату отношения сторон и потом их выстраивать. Например взять за l = 100 точек. Пройтись по всем изображениям, привести все длины или высоты к формату n * l. Другую сторону привести к m * l подрезкой и отсюда уже выстраивать. Ну это общий план начала действий. А вообще эта задача похожа на "задачу укладки рюкзака". Погуглите, может какие нить идеи в голову придут.
Ответ написан
65536
@65536
сидеть и целенаправленно думать на эту тему, пробовать сделать, тогда получится рано или поздно))

можно сделать дубово, игнорировать пропорции картинок, делать все квадратами или прямоугольниками одинаковыми. например есть 6 картинок, одну рисуем большую (можно в реальных пропорциях), под ней/сбоку рисуем 5 одинаковых, у которых ширина (если под/над большой) или высота (если сбоку) равна размеру большой картинки разделить на 5. если 7 картинок, то одну большую а под ней 2 ряда по 3, опять же с такими габаритами чтобы заполнило нужную ширину/высоту. такой алгоритм сделать не сложно, это арифметика.

а в квадраты уже вписывать картинки так чтобы они заняли их целиком (обрезать)

вот могу взгреть свой вписыватель
class Wrapper
{
    private $sourceWidth;
    private $sourceHeight;

    public function sourceSize($width, $height)
    {
        $this->sourceWidth = $width;
        $this->sourceHeight = $height;

        return $this;
    }

    private $targetWidth;
    private $targetHeight;

    public function targetSize($width = false, $height = false)
    {
        $this->targetWidth = $width;
        $this->targetHeight = $height;

        return $this;
    }

    private $preventUpsize = false;

    public function preventUpsize($value = true)
    {
        $this->preventUpsize = $value;

        return $this;
    }

    private $ratio;
    private $left;
    private $top;
    private $width;
    private $height;

    /**
     * растянуть/сжать так, чтобы source полностью поместилось в target
     */
    public function fit()
    {
        $sourceRatio = $this->sourceWidth / $this->sourceHeight;

        if (!$this->targetWidth || !$this->targetHeight) {
            if ($this->targetWidth) {
                $this->targetHeight = $this->targetWidth / $sourceRatio;
            } elseif ($this->targetHeight) {
                $this->targetWidth = $sourceRatio / $this->targetHeight;
            }

            $targetRatio = $sourceRatio;
        } else {
            $targetRatio = $this->targetWidth / $this->targetHeight;
        }

        if ($sourceRatio > $targetRatio) {
            $this->ratio = $this->targetWidth / $this->sourceWidth;
        } else {
            $this->ratio = $this->targetHeight / $this->sourceHeight;
        }

        $this->resize();
        $this->center();

        return $this->getOutput();
    }

    /**
     * растянуть/сжать так, чтобы source заняло все пространство target
     */
    public function fill()
    {
        $sourceRatio = $this->sourceWidth / $this->sourceHeight;

        if (!$this->targetWidth || !$this->targetHeight) {
            if ($this->targetWidth) {
                $this->targetHeight = $this->targetWidth / $sourceRatio;
            } elseif ($this->targetHeight) {
                $this->targetWidth = $sourceRatio / $this->targetHeight;
            }

            $targetRatio = $sourceRatio;
        } else {
            $targetRatio = $this->targetWidth / $this->targetHeight;
        }

        if ($sourceRatio < $targetRatio) {
            $this->ratio = $this->targetWidth / $this->sourceWidth;
        } else {
            $this->ratio = $this->targetHeight / $this->sourceHeight;
        }

        $this->resize();
        $this->center();

        return $this->getOutput();
    }

    private function resize()
    {
        if ($this->preventUpsize && $this->ratio > 1) {
            $this->ratio = 1;
        }

        $this->width = $this->sourceWidth * $this->ratio;
        $this->height = $this->sourceHeight * $this->ratio;
    }

    private function center()
    {
        $this->left = ($this->targetWidth - $this->width) / 2;
        $this->top = ($this->targetHeight - $this->height) / 2;
    }

    private function getOutput()
    {
        return [
            'left'   => $this->left,
            'top'    => $this->top,
            'width'  => $this->width,
            'height' => $this->height
        ];
    }
}


Должны быть известны размеры картинки и прямоугольника, который надо заполнить картинкой. То есть вам надо сначала повычислять размеры этих прямоугольников, а потом под них ресайзить картинки. Примерно так:
$wrapper = new Wrapper;

$wrapper->sourceSize($imageWidth, $imageHeight);
$wrapper->targetSize($containerWidth, $containerHeight);

$wrapData = $wrapper->fill();

$wrapData будет содержать нужную ширину и высоту и смещение (центрирующее)

Эти данные можно уже использовать где угодно, в хтмл или в джс. Я прямо в стили хтмл пишу (никто не умер):

<div class="image_wrapper" style="width: {WRAPPER_WIDTH}; height: {WRAPPER_HEIGHT};">
    <div style="left: {LEFT}px; top: {TOP}px">
        <img src="{SRC}" width="{WIDTH}" height="{HEIGHT}">
    </div>
</div>


WRAPPER_WIDTH - $containerWidth
WRAPPER_HEIGHT - $containerHeight
LEFT - $wrapData['left']
TOP - $wrapData['top']
WIDTH - $wrapData['width']
HEIGHT - $wrapData['height']

цсс такой нужен
.image_wrapper {
    position: relative;
    overflow: hidden;

    > div {
        position: relative;
    }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы