Как "интеллектуальное изменение размера" отображаемого изображения в исходное соотношение сторон

У меня есть приложение, в котором конечные пользователи могут сортировать и размещать изображения в дизайнере. Поскольку спецификация требует, чтобы изображение было "растянуто" до содержащего элемента управления, конечный пользователь может в конечном итоге получить неудобно растянутое изображение.

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

Быстрый способ решить это - фактически предоставить два варианта: 1) масштаб от ширины 2) от высоты. Пользователь выбирает метод, и алгоритм регулирует размер изображения, используя исходное соотношение сторон. Например: изображение отображается как 200x200 на дизайнере, но исходное изображение имеет разрешение 1024x768 пикселей. Пользователь выбирает "Умный размер по ширине", а новый размер становится ~ 200x150, так как исходное соотношение сторон составляет ~ 1.333

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

Ответ 1

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

original_ratio = original_width / original_height
designer_ratio = designer_width / designer_height
if original_ratio > designer_ratio
    designer_height = designer_width / original_ratio
else
    designer_width = designer_height * original_ratio

Часто вы будете работать с целыми координатами, но деления для создания коэффициентов выше должны быть плавающей точкой. Здесь перестановка формулы должна быть более целостной. Убедитесь, что ваши целые числа имеют диапазон для обработки максимальной ширины * высоты.

if original_width * designer_height > designer_width * original_height
    designer_height = (designer_width * original_height) / original_width
else
    designer_width = (designer_height * original_width) / original_height

Ответ 2

Вот решение, с которым я столкнулся, когда приходится иметь дело с этой проблемой. Оказалось довольно короткое и прямое imo, просто захотелось поделиться им.

Удобные "формулы": ratio = W / H W = H * ratio H = W / ratio

  • Рассчитайте соотношение.
  • Рассчитайте высоту изображения, если вы установите ширину в ширину нового размера (максимально допустимая ширина).
  • Рассчитайте ширину изображения, если вы установите высоту на новую высоту размера (максимально допустимая высота).
  • Посмотрите, какой из двух размеров не отменяет максимальный размер в любом измерении. Если отношение не 1, то один из них всегда будет неправильным, и всегда будет правильно.

В Javascript

// Returns array with new width and height
function proportionalScale(originalSize, newSize)
{
    var ratio = originalSize[0] / originalSize[1];

    var maximizedToWidth = [newSize[0], newSize[0] / ratio];
    var maximizedToHeight = [newSize[1] * ratio, newSize[1]];

    if (maximizedToWidth[1] > newSize[1]) { return maximizedToHeight; }
    else { return maximizedToWidth; }
}

originalSize и newSize - массив [0] = width, [1] = height

Ответ 3

Я также хотел знать это, и все, что я видел, было бесконечными примерами масштабирования ширины ИЛИ высоты, но оставляло другие переполненными.

  • Изменение ширины и высоты без необходимости циклы
  • Не превышает исходные размеры изображений

.

private void ResizeImage(Image img, double maxWidth, double maxHeight)
{
  double srcWidth = img.Source.Width;
  double srcHeight = img.Source.Height;

  double resizeWidth = srcWidth;
  double resizeHeight = srcHeight;

  double aspect = resizeWidth / resizeHeight;

  if (resizeWidth > maxWidth)
  {
    resizeWidth = maxWidth;
    resizeHeight = resizeWidth / aspect;
  }
  if (resizeHeight > maxHeight)
  {
    aspect = resizeWidth / resizeHeight;
    resizeHeight = maxHeight;
    resizeWidth = resizeHeight * aspect;
  }

  img.Width = resizeWidth;
  img.Height = resizeHeight;
}

Ответ 4

Принял предложение выше и сделал его масштабирование вверх/вниз в пределах максимальной высоты/ширины. Здесь код python для него, а также добавлена ​​поддержка вращающихся вещей, сохраняя в пределах limites:

def _resize (изображение, размеры, rotate = None):    ""       Изменяет размер изображения как можно ближе к указанным размерам. Изображение - это       django image-model-field.

    Will both scale up and down the image to meet this while keeping the proportions
    in width and height

"""

if image and os.path.isfile(image.path):

    im = pil.open(image.path)
    logging.debug('resizing image from %s x %s --> %s x %s ' % (im.size[0], im.size[1], dimensions[0], dimensions[1]))

    if rotate:
        logging.debug('first rotating image %s' % rotate)
        im = im.rotate(90)

    srcWidth = Decimal(im.size[0])
    srcHeight = Decimal(im.size[1])

    resizeWidth = srcWidth
    resizeHeight = srcHeight

    aspect = resizeWidth / resizeHeight # Decimal

    logging.debug('resize aspect is %s' % aspect)

    if resizeWidth > dimensions[0] or resizeHeight > dimensions[1]:
        # if width or height is bigger we need to shrink things
        if resizeWidth > dimensions[0]:
            resizeWidth = Decimal(dimensions[0])
            resizeHeight = resizeWidth / aspect

        if resizeHeight > dimensions[1] :
            aspect = resizeWidth / resizeHeight
            resizeHeight = Decimal(dimensions[1])
            resizeWidth = resizeHeight * aspect

    else:
        # if both width and height are smaller we need to increase size
        if resizeWidth < dimensions[0]:
            resizeWidth = Decimal(dimensions[0])
            resizeHeight = resizeWidth / aspect

        if resizeHeight > dimensions[1] :
            aspect = resizeWidth / resizeHeight
            resizeHeight = Decimal(dimensions[1])
            resizeWidth = resizeHeight * aspect

    im = im.resize((resizeWidth, resizeHeight), pil.ANTIALIAS)

    logging.debug('resized image to %s %s' % im.size)
    im.save(image.path)

else:
    # no action, due to no image or no image in path
    pass

return image

Ответ 5

Рассчитайте новые размеры для обоих вариантов ( "масштаб по ширине" и "масштаб по высоте" ), затем используйте ту, которая подходит на дисплее.

В качестве альтернативы вы также можете рассчитать соотношение сторон "ограничительной рамки" и сравнить его с соотношением сторон исходного изображения. В зависимости от того, какое соотношение сторон больше, нужно масштабировать высоту или ширину.

Вы также можете ограничить процесс изменения размера, чтобы во всех случаях выполнялось "масштабирование по ширине". Затем, чтобы изменить размер изображения, пользователь всегда должен менять свою ширину. Высота всегда будет автоматически отрегулирована.

Ответ 6

Поскольку вы хотите максимизировать максимально возможное масштабированное изображение (оригинала) в вашем окне, т.е. область в вашем дизайнере, вы должны использовать большую или ширину или высоту исходного изображения, и масштаб что до 200. Псевдокод (ширина, высота - размеры оригинала):

if (width > height) {
    scaledWidth = 200;
    scaledHeight = (height * 200) / width;
} else {
    scaledHeight = 200;
    scaledWidth = (width * 200) / height;
}

Ответ 7

Мое решение уменьшить и увеличить размер в javascript на основе fooobar.com/questions/571271/...

var scale =  function (srcWidth, srcHeight, maxWidth, maxHeight) {

      let resizeWidth  = srcWidth;
      let resizeHeight = srcHeight;

      let aspect = resizeWidth / resizeHeight;
      let scaleX = maxWidth / srcWidth;
      let scaleY = maxHeight / srcHeight;
      let scale  = Math.min(scaleX, scaleY);

      resizeWidth *= scale;
      resizeHeight *= scale;

      if (resizeWidth > maxWidth) {
        resizeWidth  = maxWidth;
        resizeHeight = resizeWidth / aspect;
      }

      if (resizeHeight > maxHeight) {
        aspect       = resizeWidth / resizeHeight;
        resizeHeight = maxHeight;
        resizeWidth  = resizeHeight * aspect;
      }

      return {
        width : resizeWidth,
        height: resizeHeight,
      };
    }

Ответ 8

Вам просто нужно выработать масштаб, необходимый для обоих измерений, а затем взять меньший из 2.

Ответ 9

вот мое решение,

a = аспект sw = исходная ширина изображения sh = исходная высота изображения dw = запрашиваемая максимальная ширина dh = запрошенная максимальная высота

sw и sh будут содержать окончательные измененные значения

code - это PHP:

$a = $sw / $sh;

if($a > 1){
    //  wider image
    if($sw != $dw){
        $rt = $dw / $sw;
        $sw = $sw * $rt;
        $sh = $sh * $rt;
    }

    if($sh > $dh){
        $rt = $dh / $sh;
        $sw = $sw * $rt;
        $sh = $sh * $rt;
    }
}else{
    //  taller image
    if($sh != $dh){
        $rt = $dh / $sh;
        $sh = $sh * $rt;
        $sw = $sw * $rt;
    }

    if($sw > $dw){
        $rt = $dw / $sw;
        $sh = $sh * $rt;
        $sw = $sw * $rt;
    }
}

Ответ 10

Я использовал этот способ для изменения размера изображения до пути FHD.

if ( width >= height) {
  var original_ratio = width / height
  new_width = 1080 * original_ratio
  console.log("new new_width = " + Math.round(new_width) );
  console.log("new new_height = 1080");
} else {
  var original_ratio =  height / width
  new_height = 1080 * original_ratio
  console.log("new new_height = " + Math.round(new_height) );
  console.log("new new_width = 1080");
}

вы можете изменить 1080 на новый размер.

Я надеюсь, что это будет полезно для кого-то хотя бы.