Какая математика позади фонового размера CSS: обложка

Я создаю "генератор изображений", где пользователи могут загружать изображение и добавлять текст и/или рисовать на нем. Выведенное изображение является фиксированным размером (698x450).

На стороне клиента, когда пользователь загружает свое изображение, он устанавливается в качестве фона div, который имеет размер 698x450 с обложкой background-size:. Это заставляет его хорошо заполнять область.

Конечное комбинированное изображение генерируется PHP с использованием функций GD. Мой вопрос: как я могу получить изображение для масштабирования в PHP так же, как в CSS. Я хочу, чтобы результат PHP скрипт выглядел так же, как если бы изображение было установлено в CSS, как было выше. Кто-нибудь знает, как браузеры используют фоновый размер: обложка подсчитывает, как масштабировать изображение соответствующим образом? Я хочу перевести это на PHP.

Спасибо

Ответы

Ответ 1

Вот логика расчета покрытия.

У вас есть четыре базовых значения:

imgWidth // your original img width
imgHeight

containerWidth // your container  width (here 698px)
containerHeight

Два отношения, полученные из этих значений:

imgRatio = (imgHeight / imgWidth)       // original img ratio
containerRatio = (containerHeight / containerWidth)     // container ratio

Вы хотите найти два новых значения:

finalWidth // the scaled img width
finalHeight

Итак:

if (containerRatio > imgRatio) 
{
    finalHeight = containerHeight
    finalWidth = (containerHeight / imgRatio)
} 
else 
{
    finalWidth = containerWidth 
    finalHeight = (containerWidth / imgRatio)
}

... и у вас есть эквивалент фона: размер.

Ответ 2

При использовании background-size: cover он масштабируется до наименьшего размера, который покрывает весь фон.

Итак, где он тоньше, чем высокий, масштабируйте его до тех пор, пока его ширина не станет такой же, как область. Где он выше, чем он тонкий, масштабируйте его до тех пор, пока его высота не станет такой же, как область.

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

Ответ 3

Спасибо mdi за то, что указали мне в правильном направлении, но это показалось не совсем правильным. Это решение, которое сработало для меня:

    $imgRatio = $imageHeight / $imageWidth;
    $canvasRatio = $canvasHeight / $canvasWidth;

    if ($canvasRatio > $imgRatio) {
        $finalHeight = $canvasHeight;
        $scale = $finalHeight / $imageHeight;
        $finalWidth = round($imageWidth * $scale , 0);
    } else {
        $finalWidth = $canvasWidth;
        $scale = $finalWidth / $imageWidth;
        $finalHeight = round($imageHeight * $scale , 0);
    }

Ответ 4

Я знаю, что это очень старый вопрос, но ответ, который я написал, на самом деле чист, используя max и mins для отношений между изображениями вместо каждого изображения с собой:

var originalRatios = {
  width: containerWidth / imageNaturalWidth,
  height: containerHeight / imageNaturalHeight
};

// formula for cover:
var coverRatio = Math.max(originalRatios.width, originalRatios.height); 

// result:
var newImageWidth = imageNaturalWidth * coverRatio;
var newImageHeight = imageNaturalHeight * coverRatio;

Мне нравится этот подход, потому что он очень систематический - может быть, это неправильное слово. Я имею в виду, что вы можете избавиться от операторов if и заставить его работать в виде "математической формулы" (input = output, если это имеет смысл):

var ratios = {
  cover: function(wRatio, hRatio) {
    return Math.max(wRatio, hRatio);
  },

  contain: function(wRatio, hRatio) {
    return Math.min(wRatio, hRatio);
  },

  // original size
  "auto": function() {
    return 1;
  },

  // stretch
  "100% 100%": function(wRatio, hRatio) {
    return { width:wRatio, height:hRatio };
  }
};

function getImageSize(options) {
  if(!ratios[options.size]) {
    throw new Error(size + " not found in ratios");
  }

  var r = ratios[options.size](
    options.container.width / options.image.width,
    options.container.height / options.image.height
  );

  return {
    width: options.image.width * (r.width || r),
    height: options.image.height * (r.height || r)
  };
}

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