2014-03-31 260 views
0

我使用下面的代码来缩放jpeg,我从互联网上的一个示例中获得了ZoomOutJpeg()函数。调整jpeg图像大小?

//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. 当我使用​​因子是0.23时,它经常发生错误,并且结果图像被损坏。我怎样才能解决它,我真的想要扩大任何因素。

  4. 最后,如果有人有任何其他算法或库来缩放jpeg,那会给出最佳性能,请介绍一下。

非常感谢!

Ť&Ť

+1

'jmp_buf setjmp_buffer;'。这足以告诉你;这不是好的代码。 – MSalters

回答

0
  1. 输出像素值被至多2×2的输入附近基础上的。这自动意味着缩放因子被限制为1/2。超过1的比例因子需要插值,而这个代码不会这样做。
  2. 这种类型的错误处理和清理是非常脆弱的。只需使用RAII。
  3. 通过0.23进行缩放,每个输出像素需要5x5输入像素,这是该代码无法做到的。
  4. 图书馆的请求与SO无关,只是使用搜索引擎。
+0

谢谢! 请参阅我的另一个问题http://stackoverflow.com/questions/22859843/image-is-damaged-when-using-jpegbitmapencoder – TTGroup