调整jpeg图像的大小?

时间:2014-03-31 04:14:53

标签: c++ .net libjpeg

我正在使用以下代码来扩展jpeg,我从互联网上的一个例子中得到了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);时是否存在任何潜在问题?

  3. 当我使用因果为ZoomOutJpeg()的{​​{1}}时,通常会出现错误,并且结果图像已损坏。我该如何解决它,我真的想用任何因子进行缩放。

  4. 最后,如果有人有任何其他算法或库来扩展jpeg,那么性能最佳,请介绍我。

  5. 非常感谢!

    T&amp; T公司

1 个答案:

答案 0 :(得分:0)

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