缩放图片长和宽控制图片文件尺寸
作者: 刘鹏
日期: 2010-11-08
本文详细研究了如何通过缩放图片来控制图片文件大小。

简介

在一些场合上传图片时,会限制图片文件的大小,如上传头像,若待上传的图片文件太大就需要对图片压缩,压缩图片有很多方法,这里我们讨论的是如何通过改变图片的长和宽来达到缩小图片文件尺寸的目的。这个问题我们可以表述如下:

给定一图片文件(格式不限),文件大小为 S,如何通过缩放图片的长和宽,使 S < M,并要求缩放后长、宽比例与原来保持一致。

思路

设图片的长缩小 wr 倍,图片的宽缩小 hr 倍,则对于图片的像素数据来讲,相当于 wr*hr 个像素合并成一个像素。由此我们可以近似的认为图片文件的尺寸缩小了 wr*hr 倍。根据着这个思路,我们就可以求解我们的问题。

假设一图片长、宽比为 a,为了把图片文件大小压缩到 M 以下,图片文件的大小需要缩小 b 倍,为此图片的长需缩小 wr 倍,图片的宽缩小 hr 倍,由此,我们可以得到一个二元一次方程:

  wr / hr = a   (a>=1)
  wr * hr = b

通过解这个方程,我们得到


  wr = squar (b*a)
  hr = squar (b/a)

代码样例

根据上面的思路,我们基于 QT 接口实现的伪代码如下所示:


/*
 * Resize image in to out which make file size is less bound
 * in, input image file
 * out, output image file
 * bound, file size limit
 */

void compressImageByResize (char *in, char* out, qint64 bound)
{

    int w,h;
    int imageWidth, imageHeight;
    float sizeRadio,whRadio;
    bool isPortrait = false;


    qint64 fileSize = 0;
    QFile *file = new QFile (in);
    fileSize = file->size();
    delete file;


    QImage *imgInput = new QImage (in);
    imageWidth = imgInput->width ();
    imageHeight = imgInput->height();
    if (imageWidth < imageHeight)
        isPortrait = true;


    sizeRadio = ceil(fileSize/bound);

    if (isPortrait)
        whRadio = ceil(imageHeight/imageWidth);
    else
        whRadio = ceil(imageWidth/imageHeight);

    float wScale = ceil(sqrt(sizeRadio * whRadio));
    float hSacle = ceil(sqrt(sizeRadio / whRadio));

    if (isPortrait) {
        w = imageWidth / hScale;
        h = imageHeight / wScale;
    }
    else {
        w = imageWidth / wScale;
        h = imageHeight / hScale;
    }

    QImage imgOutput = imgInput->scaled (w,h);
    imgOutput.save (out);

    delete imgOutput;

}

注:

需要保证 whRadio >= 1,即

当 width >= height 时,


    whRadio = imageWidth/imageWidth
    w = imageWidth / wScale;
    h = imageHeight / hScale;


当 height > width 时,


    whRadio = imageHeight/imageWidth
    w = imageWidth / hScale
    h = imageHeight / wScale