математика / алгоритм Подгонка изображения к экрану с сохранением пропорций - PullRequest
37 голосов
/ 04 июля 2011

Мне нужна помощь с математикой / алгоритмом для получения изображения известного размера и подгонки под одно из двух размеров экрана:

720 x 480 или 1280 x 1024.

Размеры изображенияИсходя из XML-файла, однако эти измерения являются веб-измерениями, я также получаю выборку изображений из XML, которые могут иметь более высокое и более низкое разрешение, чем веб-измерения.

Я хочу использовать соотношение сторон веб-размеров для отображения изображения с более высоким разрешением, если оно доступно, на экране HD (1280x720) или, если пользователь находится на экране SD (720x480)отобразить изображение на этом экране.

Другие вещи, которые были бы полезны для этого, но с более низким приоритетом, были бы, если бы я знал, что разрешение изображения в обоих измерениях меньше, чем у экрана SD (в этом случае все, что я знаю, это Интернетразмер и горизонтальный размер файла изображения), чтобы отобразить его как фактический размер на этом экране.

Надеюсь, это достаточно ясно.

Спасибо!

Ответы [ 4 ]

132 голосов
/ 04 июля 2011

Общий как может быть:

Данные изображения: (w i , h i ) и определение r i = w i / h i
Разрешение экрана: (w s , h s ) и определение r s = w s / h s

Размеры масштабированного изображения:

rs > ri ? (wi * hs/hi, hs) : (ws, hi * ws/wi)

Так, например:

         20
|------------------|
    10
|---------|

--------------------     ---   ---
|         |        |      | 7   |
|         |        |      |     | 10
|----------        |     ---    |
|                  |            |
--------------------           ---

ws = 20
hs = 10
wi = 10
hi = 7

20/10 > 10/7 ==> (wi * hs/hi, hs) = (10 * 10/7, 10) = (100/7, 10) ~ (14.3, 10)

Который, как вы можете видеть, четко масштабируется до размера экрана, потому что высота соответствует высоте экрана, но четко сохраняет соотношение сторон с 14.3/10 ~ 10/7

UPDATE

Центрируйте изображение следующим образом:

вызов (w новый , h новый ) новых размеров.

top = (hs - hnew)/2
left = (ws - wnew)/2
10 голосов
/ 08 августа 2015

Здесь это просто C.

Вы хотите масштабировать обе координаты по возвращаемому коэффициенту масштабирования.

/* For a rectangle inside a screen, get the scale factor that permits the rectangle
   to be scaled without stretching or squashing. */
float 
aspect_correct_scale_for_rect(const float screen[2], const float rect[2])
{
    float screenAspect = screen[0] / screen[1];
    float rectAspect = rect[0] / rect[1];

    float scaleFactor;
    if (screenAspect > rectAspect)
        scaleFactor = screen[1] / rect[1];
    else
        scaleFactor = screen[0] / rect[0];

    return scaleFactor;
}

4 голосов
/ 12 февраля 2015

Коррекция соотношения сторон с помощью почтового ящика или подгонки к экрану

Недавно я написал метод для решения этой проблемы в iOS. Я использую библиотеку Eigen matrix для масштабирования, но принцип (коэффициент масштабирования) тот же, без матриц.

Eigen::Matrix4x4f aspectRatioCorrection(bool fillScreen, const Eigen::Vector2f &screenSize, const Eigen::Vector2f &imageSize)
{
    Eigen::Matrix4x4f scalingMatrix(Eigen::Matrix4x4f::Identity());

    float screenWidth = screenSize.x();
    float screenHeight = screenSize.y();
    float screenAspectRatio = screenWidth / screenHeight;
    float imageWidth = imageSize.x();
    float imageHeight = imageSize.y();
    float imageAspectRatio = imageWidth / imageHeight;

    float scalingFactor;
    if (fillScreen) {
        if (screenAspectRatio > imageAspectRatio) {
            scalingFactor = screenWidth / imageWidth;
        } else {
            scalingFactor = screenHeight / imageHeight;
        }
    } else {
        if (screenAspectRatio > imageAspectRatio) {
            scalingFactor =  screenHeight / imageHeight;
        } else {
            scalingFactor = screenWidth / imageWidth;
        }
    }

    scalingMatrix(0, 0) = scalingFactor;
    scalingMatrix(1, 1) = scalingFactor;

    return scalingMatrix;
}
3 голосов
/ 04 мая 2018

Я понимаю принятый ответ, и он работает, но я всегда находил следующий метод более простым и лаконичным для «наилучшего соответствия»:

// prep
let maxWidth = 190,
    maxHeight = 150;
let imgWidth = photo.width,
    imgHeight = photo.height;

// calc
let widthRatio = maxWidth / imgWidth,
    heightRatio = maxHeight / imgHeight;
let bestRatio = Math.min(widthRatio, heightRatio);

// output
let newWidth = imgWidth * bestRatio,
    newHeight = imgHeight * bestRatio;
...