数学/算法使图像适合屏幕保持纵横比

时间:2011-07-03 21:34:27

标签: algorithm image math graphics resize

我需要数学/算法的帮助来拍摄已知大小的图像并适合两个屏幕尺寸之一:

720 x 480或1280 x 1024。

图像尺寸来自XML文件,但是这些尺寸是Web尺寸,我还从XML中选择可能比Web尺寸更高和更低分辨率的图像。

我想要的是使用网页尺寸的宽高比在HD(1280x720)屏幕上显示更高分辨率的图像(如果有),或者,如果用户在SD屏幕上(720x480)显示图像在那个屏幕上。

如果我知道图像的分辨率在两个维度上都比SD屏幕小(在这种情况下,我所知道的是网络维度,并且图像文件的水平尺寸),以在屏幕上显示为实际尺寸。

希望足够清楚。

谢谢!

4 个答案:

答案 0 :(得分:128)

通用可以:

图像数据:(w i ,h i )并定义r i = w i / h <子> I
屏幕分辨率:(w s ,h s )并定义r s = w s / h 小号

缩放图像尺寸:

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

<强>更新

将图像居中,如下所示:

调用(w new ,h new )新维度。

top = (hs - hnew)/2
left = (ws - wnew)/2

答案 1 :(得分:10)

这是直截了当的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;
}

答案 2 :(得分:4)

使用letterboxing或fit-to-screen进行宽高比校正

我最近编写了一个方法来处理iOS中的这个问题。我正在使用特征矩阵库进行缩放,但原则(缩放因子)在没有矩阵的情况下是相同的。

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 :(得分:3)

我理解接受的答案并且有效,但我总是发现以下方法更简单,更简洁,以便“最适合”:

// 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;