Click to See Complete Forum and Search --> : Decompress JPEG


kevinbrianwhite
May 25th, 1999, 12:33 PM
Can anybody point me in the right direction -
I need to be able to decompress a jpg from memory. I am using Independent JPEG Group's JPEG library. They have examples on reading and decompressing a jpeg from a file but I want to read a jpg from a webserver into memory. In memory, I want to decompress the jpeg and do something with it. I know how to get the jpg from a webserver. Does anybody have any experience with do something like this? Independent JPEG Group's mentions that I have to create a custom source manager???

Wes Rogers
May 25th, 1999, 03:44 PM
Dear Kevin,

Take a look at "paintlib", which can be downloaded from the bitmap and graphics section of this site.

I seem to recall that it had a way of reading a jpeg file and turning it into a bitmap for display.

Hope this helps,
Wes Rogers

jck
May 25th, 1999, 04:14 PM
Consult the decompression example in the example.c file from IJG -- using this code I was able to put together a simple decompression function to decompress from a jpeg to a 24 bpp dib, the code for which follows. The trick with converting jpegs to Windows dibs is that there are two big format differences between the two: (i) jpeg rows are ordered top to bottom, while in Windows dibs rows are ordered bottom to top and (ii) jpeg RGBs are in true RGB order, while Windows dib RGBs are actually in BGR order -- the "for" loop in the enclosed code does both reversals.

This code is part of a simple 24 bpp DIB class I put together (which I assume you have, or can whip up, your own version of) and refers to several member variables and functions of that class -- m_Width (of new dib, in pixels), m_Height (of new dib, in pixels), m_pData (unsigned char* -- holds image RGB data) and Create (creates a new dib, given width, height and a name) -- of course, you will have to substitute the names for the analogous members from your class.

What I have been working on is a class that takes a jpeg, converts it to a dib and then does the necessary byte reordering and sizing to be used as an OpenGL texture -- in OpenGL, for a dib to work as a texture, width and height pixel dimensions must both be powers of two, and the RGB byte ordering is true RGB (that is, like jpeg, not Windows dib). If I get it done anytime soon maybe I'll send it in. In working on the project I have found the following very helpful:

1. The IJG materials you referred to -- especially the libjpeg text file (which provides an overview) and the example.c mentioned above.
2. Wes Rogers' article on DIB to JPEG compression in CodeGuru's "Bitmaps & Palletes" section.
3. Pierre Alliez's submission to CodeGuru's "OpenGL" section, which covers dibs and OpenGL (it does RGB reordering, but not power-of-two resizing), but does not cover jpeg.
4. Dale Rogerson's OpenGL articles on MSDN (which cover OpenGL and dibs, but not jpeg).
5. Chris Losinger of smalleranimals.com has made a number of useful submissions to CodeGuru and his site offers inexpensive as well as freewear image processing programs.
6. Ulrich von Zadow's PaintLib (which is referenced in CodeGuru -- either in "Bitmaps & Palettes", "Misc" or "Links") is a very comprehensive image processing tool (supporting many formats), though I have not put in the effort to get it running.

Note that someone may suggest using new Win 32 GDI extensions for the decompression. While I think this helps for the display of jpegs (and pngs), I do not think it can be used to decompress into a dib (see the following MSDN article):

"JPEG and PNG Extensions for Specific Bitmap Functions and Structures
Starting with the Microsoft® Windows® 98 and Windows NT® 5.0 operating systems, the StretchDIBits <bitmaps_1ppv.htm> and SetDIBitsToDevice <bitmaps_8e5h.htm> functions have been extended to allow JPEG and PNG images to be passed as the source image to printer devices. This extension is not intended as a means to supply general JPEG and PNG decompression to applications, but rather to allow applications to send JPEG- and PNG-compressed images directly to printers having hardware support for JPEG and PNG images.
The BITMAPINFOHEADER <bitmaps_1rw2.htm>, BITMAPV4HEADER <bitmaps_2k1e.htm> and BITMAPV5HEADER <bitmaps_7c36.htm> structures are extended to allow specification of biCompression values indicating that the bitmap data is a JPEG or PNG image. These compression values are only valid for SetDIBitsToDevice and StretchDIBits when the hdc parameter specifies a printer device. To support metafile spooling of the printer, the application should not rely on the return value to determine whether the device supports the JPEG or PNG file. The application must issue QUERYESCSUPPORT with the corresponding escape before calling SetDIBitsToDevice and StretchDIBits. If the validation escape fails, the application must then fall back on its own JPEG or PNG support to decompress the image into a bitmap."

I hope the foregoing is helpful.


BOOL CTexture::CreateFromJpeg(CString csJpeg) //Pathname to jpeg file
{
if (csJpeg == "")
{
AfxMessageBox("Invalid input data.");
return FALSE;
}
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
FILE* pInFile; //Source JPEG file
if ((pInFile = fopen(csJpeg, "rb")) == NULL)
{
AfxMessageBox("Cannot open " + csJpeg + ".");
return FALSE;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, pInFile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
//Create empty DIB of proper size
CString csBmp = csJpeg.SpanExcluding(".");
csBmp += ".bmp";
Create(cinfo.output_width, cinfo.output_height, csBmp);
//Allocate single row of JSAMPs
JSAMPARRAY jsmpPixels = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo,
JPOOL_IMAGE,
cinfo.image_width * cinfo.output_components,
1);
LPBYTE lpPixels = (LPBYTE)m_pData;
unsigned int nBytesWide = (m_Width * 3);
unsigned int nUnused = (((nBytesWide + 3) / 4) * 4) - nBytesWide;
nBytesWide += nUnused;
unsigned int q, nRow, nPixel;
while (cinfo.output_scanline < cinfo.output_height)
{
jpeg_read_scanlines(&cinfo, jsmpPixels, 1);
for (q=0; q < (nBytesWide-nUnused); q+=3)
{
nRow = (m_Height - cinfo.output_scanline) * nBytesWide;
nPixel = nRow + q;
lpPixels[nPixel+2] = jsmpPixels[0][q+0]; //Red
lpPixels[nPixel+1] = jsmpPixels[0][q+1]; //Green
lpPixels[nPixel+0] = jsmpPixels[0][q+2]; //Blue
}
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(pInFile);
return TRUE;
}