繁体   English   中英

调整jpeg图片大小?

[英]Resize jpeg image?

我正在使用以下代码缩放jpeg,我从Internet上的示例获得了ZoomOutJpeg()函数。

//JpegLib Error Handing - Begin
struct my_error_mgr
{
    struct jpeg_error_mgr pub;  /* "public" fields */

    jmp_buf setjmp_buffer;  /* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;

/*
* Here's the routine that will replace the standard error_exit method:
*/

METHODDEF(void)
my_error_exit(j_common_ptr cinfo)
{
    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
    my_error_ptr myerr = (my_error_ptr)cinfo->err;

    /* Always display the message. */
    /* We could postpone this until after returning, if we chose. */
    (*cinfo->err->output_message) (cinfo);

    /* Return control to the setjmp point */
    longjmp(myerr->setjmp_buffer, 1);
}
//JpegLib Error Handing - End

/*
* zoom out picture. the factor should between 0.5 and 1.0. It can be 0.5, but can not be 1.0.
*/
bool ZoomOutJpeg(UINT8 *inBuff, UINT8 *outBuff, UINT32 inSize, UINT32* _outSize, float factor)
{   
    //if (factor > 1 || factor < 0.5f)
    //  return false;

    // init decompress struct
    struct jpeg_decompress_struct in;
    JSAMPROW inRowPointer[1];
    // init compress struct
    struct jpeg_compress_struct out;    
    JSAMPROW outRowPointer[1];
    struct my_error_mgr jerrIn;
    struct my_error_mgr jerrOut;

    /* We set up the normal JPEG error routines, then override error_exit. */
    in.err = jpeg_std_error(&jerrIn.pub);   
    jerrIn.pub.error_exit = my_error_exit;
    /* Establish the setjmp return context for my_error_exit to use. */
    if (setjmp(jerrIn.setjmp_buffer))
    {
        jpeg_destroy_decompress(&in);
        return false;
    }
    jpeg_create_decompress(&in);
    jpeg_mem_src(&in, inBuff, inSize);
    jpeg_read_header(&in, TRUE);
    jpeg_start_decompress(&in);

    out.err = jpeg_std_error(&jerrOut.pub);
    jerrOut.pub.error_exit = my_error_exit;
    /* Establish the setjmp return context for my_error_exit to use. */
    if (setjmp(jerrOut.setjmp_buffer))
    {
        jpeg_destroy_decompress(&in);
        jpeg_destroy_compress(&out);
        return false;
    }
    jpeg_create_compress(&out);
    jpeg_mem_dest(&out, &outBuff, (unsigned long*)_outSize);

    int width = in.output_width;
    int height = in.output_height;
    int bytesPerPixel = in.num_components;

    int destWidth = (int)(width * factor);
    int destHeight = (int)(height * factor);
    _outFrameSize->resX = destWidth;
    _outFrameSize->resY = destHeight;

    out.image_width = destWidth;
    out.image_height = destHeight;
    out.input_components = bytesPerPixel;
    out.in_color_space = JCS_RGB;

    jpeg_set_defaults(&out);
    jpeg_start_compress(&out, TRUE);

    // Process RGB data.
    int outRowStride = destWidth * bytesPerPixel;
    int inRowStride = width * bytesPerPixel;
    outRowPointer[0] = (unsigned char *)malloc(outRowStride);
    inRowPointer[0] = (unsigned char *)malloc(inRowStride);

    JSAMPROW baseInRowPointer[1];
    baseInRowPointer[0] = (unsigned char *)malloc(inRowStride);

    unsigned char bUpLeft, bUpRight, bDownLeft, bDownRight;
    unsigned char gUpLeft, gUpRight, gDownLeft, gDownRight;
    unsigned char rUpLeft, rUpRight, rDownLeft, rDownRight;
    unsigned char b, g, r;

    float fX, fY;
    int iX, iY;
    int i, j;

    int currentBaseLocation = -1;
    int count = 0;

    // Process the first line.
    jpeg_read_scanlines(&in, inRowPointer, 1);
    for (j = 0; j < destWidth; j++)
    {
        fX = ((float)j) / factor;
        iX = (int)fX;

        bUpLeft = inRowPointer[0][iX * 3 + 0];
        bUpRight = inRowPointer[0][(iX + 1) * 3 + 0];

        gUpLeft = inRowPointer[0][iX * 3 + 1];
        gUpRight = inRowPointer[0][(iX + 1) * 3 + 1];

        rUpLeft = inRowPointer[0][iX * 3 + 2];
        rUpRight = inRowPointer[0][(iX + 1) * 3 + 2];

        b = bUpLeft * (iX + 1 - fX) + bUpRight * (fX - iX);
        g = gUpLeft * (iX + 1 - fX) + gUpRight * (fX - iX);
        r = rUpLeft * (iX + 1 - fX) + rUpRight * (fX - iX);

        outRowPointer[0][j * 3 + 0] = b;
        outRowPointer[0][j * 3 + 1] = g;
        outRowPointer[0][j * 3 + 2] = r;
    }
    jpeg_write_scanlines(&out, outRowPointer, 1);

    currentBaseLocation = 0;

    //Process the other lines between the first and last.
    for (i = 1; i < destHeight - 1; i++)
    {
        fY = ((float)i) / factor;
        iY = (int)fY;

        if (iY == currentBaseLocation)
        {
            in.output_scanline = iY;
            SwapJsampRow(inRowPointer[0], baseInRowPointer[0]);
            jpeg_read_scanlines(&in, baseInRowPointer, 1);
        }
        else
        {
            in.output_scanline = iY - 1;
            jpeg_read_scanlines(&in, inRowPointer, 1);
            jpeg_read_scanlines(&in, baseInRowPointer, 1);
        }

        currentBaseLocation = iY + 1;

        for (j = 0; j < destWidth; j++)
        {
            fX = ((float)j) / factor;
            iX = (int)fX;

            bUpLeft = inRowPointer[0][iX * 3 + 0];
            bUpRight = inRowPointer[0][(iX + 1) * 3 + 0];
            bDownLeft = baseInRowPointer[0][iX * 3 + 0];
            bDownRight = baseInRowPointer[0][(iX + 1) * 3 + 0];

            gUpLeft = inRowPointer[0][iX * 3 + 1];
            gUpRight = inRowPointer[0][(iX + 1) * 3 + 1];
            gDownLeft = baseInRowPointer[0][iX * 3 + 1];
            gDownRight = baseInRowPointer[0][(iX + 1) * 3 + 1];

            rUpLeft = inRowPointer[0][iX * 3 + 2];
            rUpRight = inRowPointer[0][(iX + 1) * 3 + 2];
            rDownLeft = baseInRowPointer[0][iX * 3 + 2];
            rDownRight = baseInRowPointer[0][(iX + 1) * 3 + 2];

            b = bUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + bUpRight * (fX - iX) * (iY + 1 - fY) + bDownLeft * (iX + 1 - fX) * (fY - iY) + bDownRight * (fX - iX) * (fY - iY);
            g = gUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + gUpRight * (fX - iX) * (iY + 1 - fY) + gDownLeft * (iX + 1 - fX) * (fY - iY) + gDownRight * (fX - iX) * (fY - iY);
            r = rUpLeft * (iX + 1 - fX) * (iY + 1 - fY) + rUpRight * (fX - iX) * (iY + 1 - fY) + rDownLeft * (iX + 1 - fX) * (fY - iY) + rDownRight * (fX - iX) * (fY - iY);

            outRowPointer[0][j * 3 + 0] = b;
            outRowPointer[0][j * 3 + 1] = g;
            outRowPointer[0][j * 3 + 2] = r;
        }

        jpeg_write_scanlines(&out, outRowPointer, 1);
    }

    //Process the last line.
    in.output_scanline = height - 1;
    jpeg_read_scanlines(&in, inRowPointer, 1);
    for (j = 0; j < destWidth; j++)
    {
        fX = ((float)j) / factor;
        iX = (int)fX;

        bUpLeft = inRowPointer[0][iX * 3 + 0];
        bUpRight = inRowPointer[0][(iX + 1) * 3 + 0];

        gUpLeft = inRowPointer[0][iX * 3 + 1];
        gUpRight = inRowPointer[0][(iX + 1) * 3 + 1];

        rUpLeft = inRowPointer[0][iX * 3 + 2];
        rUpRight = inRowPointer[0][(iX + 1) * 3 + 2];

        b = bUpLeft * (iX + 1 - fX) + bUpRight * (fX - iX);
        g = gUpLeft * (iX + 1 - fX) + gUpRight * (fX - iX);
        r = rUpLeft * (iX + 1 - fX) + rUpRight * (fX - iX);

        outRowPointer[0][j * 3 + 0] = b;
        outRowPointer[0][j * 3 + 1] = g;
        outRowPointer[0][j * 3 + 2] = r;
    }
    jpeg_write_scanlines(&out, outRowPointer, 1);

    //free memory
    free(inRowPointer[0]);
    free(baseInRowPointer[0]);
    free(outRowPointer[0]);

    // close resource
    jpeg_finish_decompress(&in);
    jpeg_destroy_decompress(&in);
    jpeg_finish_compress(&out);
    jpeg_destroy_compress(&out);

    return true;
}

我对上述代码有一些疑问:

  1. 我不明白为什么作者说"zoom out picture. the factor should between 0.5 and 1.0. It can be 0.5, but can not be 1.0." 如果我将此代码与其他任何因素(例如0.22 (放大)会怎样?

  2. 使用jpeg_destroy_decompress(&in); jpeg_destroy_compress(&out);时是否存在任何潜在问题jpeg_destroy_decompress(&in); jpeg_destroy_compress(&out); jpeg_destroy_decompress(&in); jpeg_destroy_compress(&out); 在我下面的错误处理中?

  3. 当我使用ZoomOutJpeg()的因数是0.23 ,它经常发生错误,并且结果图像被损坏。 我该如何解决它,我真的想在任何方面进行扩展。

  4. 最后,如果有人使用任何其他算法或库来缩放jpeg,这些算法或库可以提供最佳性能,请向我介绍。

非常感谢你!

T&T

  1. 输出像素值最多基于2x2输入邻域。 这自动意味着比例因子限制为1/2。 比例系数大于1时需要插值,而此代码不执行插值。
  2. 这种类型的错误处理和清除非常脆弱。 只需使用RAII。
  3. 按0.23缩放需要每个输出像素5x5个输入像素,而此代码无法做到。
  4. 图书馆的要求在SO上是不合时宜的,只需使用搜索引擎即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM