Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Native support for jpeg files in Windows

80 views
Skip to first unread message

Grzegorz Wróbel

unread,
Nov 22, 2006, 2:45:37 PM11/22/06
to
Does it exist? The documantation on standard GDI library and
BITMPAPINFOHEADER mentions BI_JPEG and BI_PNG compression types but I
never saw a working code that would took advantage of that. Seems they
never finished this. But I'm pretty certain there must be some functions
provided with Windows that can open those files, most likely within the
shell, since it has possibility to display thumbnails of different images.

I would like to be able to open jpg file and convert it into 24bpp bmp
in memory, but I don't want to rely on any dll or link against external
library for that. Providing my own jpg decompressor doesn't sound like
best idea either. If operating system already has such feature I would
like to use it if possible. Any thoughts?

--
Grzegorz Wróbel
http://www.4neurons.com/
677265676F727940346E6575726F6E732E636F6D

alex

unread,
Nov 22, 2006, 2:57:36 PM11/22/06
to

"Grzegorz Wróbel" </dev/nu...@localhost.localdomain> wrote in message
news:ek29ms$fo3$1...@nemesis.news.tpi.pl...

> Does it exist? The documantation on standard GDI library and
> BITMPAPINFOHEADER mentions BI_JPEG and BI_PNG compression types but I
> never saw a working code that would took advantage of that. Seems they
> never finished this. But I'm pretty certain there must be some functions
> provided with Windows that can open those files, most likely within the
> shell, since it has possibility to display thumbnails of different images.

This had been asked and answered on microsoft.public.win32.programmer.ui


Lucian Wischik

unread,
Nov 22, 2006, 5:00:20 PM11/22/06
to
Grzegorz Wróbel </dev/nu...@localhost.localdomain> wrote:
>Does it exist? The documantation on standard GDI library and
>BITMPAPINFOHEADER mentions BI_JPEG and BI_PNG compression types but I
>never saw a working code that would took advantage of that. Seems they
>never finished this. But I'm pretty certain there must be some functions
>provided with Windows that can open those files, most likely within the
>shell, since it has possibility to display thumbnails of different images.

// LoadJpeg: given an HGLOBAL containing jpeg data, we load it.
HBITMAP LoadJpeg(HGLOBAL hglob)
{ IStream *stream=0; HRESULT
hr=CreateStreamOnHGlobal(hglob,FALSE,&stream);
if (!SUCCEEDED(hr) || stream==0) return 0;
IPicture *pic; hr=OleLoadPicture(stream, 0, FALSE, IID_IPicture,
(LPVOID*)&pic);
stream->Release();
if (!SUCCEEDED(hr) || pic==0) return 0;
HBITMAP hbm0=0; hr=pic->get_Handle((OLE_HANDLE*)&hbm0);
if (!SUCCEEDED(hr) || hbm0==0) {pic->Release(); return 0;}
//
// Now we make a copy of it into our own hbm
DIBSECTION dibs; GetObject(hbm0,sizeof(dibs),&dibs);
int w=dibs.dsBm.bmWidth, h=dibs.dsBm.bmHeight;
dibs.dsBmih.biClrUsed=0; dibs.dsBmih.biClrImportant=0; void *bits;
HDC sdc=GetDC(0);
HBITMAP
hbm1=CreateDIBSection(sdc,(BITMAPINFO*)&dibs.dsBmih,DIB_RGB_COLORS,&bits,0,0);
//
HDC hdc0=CreateCompatibleDC(sdc), hdc1=CreateCompatibleDC(sdc);
HGDIOBJ hold0=SelectObject(hdc0,hbm0),
hold1=SelectObject(hdc1,hbm1);
BitBlt(hdc1,0,0,w,h,hdc0,0,0,SRCCOPY);
SelectObject(hdc0,hold0); SelectObject(hdc1,hold1);
DeleteDC(hdc0); DeleteDC(hdc1);
ReleaseDC(0,sdc);
pic->Release();
return hbm1;
}

HBITMAP Load(const tstring fn)
{ if (fn.length()==0) return 0;
HBITMAP hbm;
tstring ext = ExtractFileExt(fn);
if (_tcsicmp(_T(".bmp"),ext.c_str())==0)
{
hbm=(HBITMAP)LoadImage(hInstance,fn.c_str(),IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
return hbm;
}
HANDLE hf =
CreateFile(fn.c_str(),GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
if (hf==INVALID_HANDLE_VALUE) return 0;
DWORD size=GetFileSize(hf,0);
HGLOBAL hglob = GlobalAlloc(GMEM_MOVEABLE,size);
void *buf=GlobalLock(hglob);
DWORD red; ReadFile(hf,buf,size,&red,0);
GlobalUnlock(hglob);
hbm = LoadJpeg(hglob);
GlobalFree(hglob);
CloseHandle(hf);
return hbm;
}


--
Lucian

Grzegorz Wróbel

unread,
Nov 22, 2006, 5:03:36 PM11/22/06
to

Thanks for the tip. I've scanned microsoft.public.win32.programmer.ui.
I found one answer that might be usable for me, it's Microsoft's LoadPic
sample, which uses IPicture interface. I've run on this sample before
but I'd prefer pure WINAPI solution if it were available.

Grzegorz Wróbel

unread,
Nov 22, 2006, 5:06:57 PM11/22/06
to

Thanks Lucian, that's pretty neat code.

ne...@rtrussell.co.uk

unread,
Nov 22, 2006, 5:09:30 PM11/22/06
to
Lucian Wischik wrote:
> DWORD red; ReadFile(hf,buf,size,&red,0);
> GlobalUnlock(hglob);
> hbm = LoadJpeg(hglob);

To read a JPEG from a file you can use OleLoadPicturePath directly,
rather than going to the trouble of using ReadFile and OleLoadPicture
separately. The only complication is that you must supply
OleLoadPicturePath with a pathname that is unambiguously a disk file
rather than a URL (e.g. by including the drive letter).

Richard.
http://www.rtrussell.co.uk/
To reply by email change 'news' to my forename.

xbunny

unread,
Nov 22, 2006, 5:41:35 PM11/22/06
to
Grzegorz Wróbel wrote:
> Does it exist? The documantation on standard GDI library and
> BITMPAPINFOHEADER mentions BI_JPEG and BI_PNG compression types but I
> never saw a working code that would took advantage of that. Seems they
> never finished this.

I have used the BI_JPEG facility a long time ago, its not supported by
the normal GDI screen graphics (or at least it wasnt then) but certain
print drivers support it (I used a tektronics phaser printer with a
postscript print driver). It is very useful rather than having to
decompress a potentially huge image and send it as hundreds of megabytes
of raw rgb to the printer you can send the jpeg data directly (with
StretchDIBits) and the printer will decompress it internally. Theres a
pretty vague example at:
http://msdn2.microsoft.com/en-us/library/ms532320.aspx

So anyways it is finished just it probably doesnt help you in this respect.

Bunny

Grzegorz Wróbel

unread,
Nov 22, 2006, 8:04:03 PM11/22/06
to

I've seen this example, what hit me there is no way to obtain width and
height of the original image, that's perhaps why it is useful only for
printing.

Grzegorz Wróbel

unread,
Nov 22, 2006, 8:22:38 PM11/22/06
to

Full path is not that trouble, however I can't get OleLoadPicturePath
working. I just successfully compiled first working version using
ReadFile + CreateStreamOnHGlobal + OleLoadPicture that converts jpg to
bmp :).

I think I can get shorter code than Lucian's, including converting to
DIB and saving. ;)

Grzegorz Wróbel

unread,
Nov 22, 2006, 11:40:51 PM11/22/06
to
Lucian Wischik wrote:
...

> // Now we make a copy of it into our own hbm
> DIBSECTION dibs; GetObject(hbm0,sizeof(dibs),&dibs);
> int w=dibs.dsBm.bmWidth, h=dibs.dsBm.bmHeight;
> dibs.dsBmih.biClrUsed=0; dibs.dsBmih.biClrImportant=0; void *bits;
> HDC sdc=GetDC(0);
> HBITMAP
> hbm1=CreateDIBSection(sdc,(BITMAPINFO*)&dibs.dsBmih,DIB_RGB_COLORS,&bits,0,0);
> //
> HDC hdc0=CreateCompatibleDC(sdc), hdc1=CreateCompatibleDC(sdc);
> HGDIOBJ hold0=SelectObject(hdc0,hbm0),
> hold1=SelectObject(hdc1,hbm1);
> BitBlt(hdc1,0,0,w,h,hdc0,0,0,SRCCOPY);

Since I am really interested in obtaining bits not HBITMAP, any method
that requires using a DC is not perfect. In my code I put the bitmap
into DC and call GetDIBits. The problem will be if the DC is 16 or 8
bits. This will hit the quality. I quess using CreateDIBSection and
BitBlting trough display's compatible DC as you do it will have the same
result.

The question is: how to ensure I get 24bpp quality even if current
display mode is 16 or 8 bits?

Chris Becke

unread,
Nov 23, 2006, 2:48:21 AM11/23/06
to

"Grzegorz Wróbel" </dev/nu...@localhost.localdomain> wrote in message
news:ek29ms$fo3$1...@nemesis.news.tpi.pl...
> Does it exist? The documantation on standard GDI library and
> BITMPAPINFOHEADER mentions BI_JPEG and BI_PNG compression types but I
> never saw a working code that would took advantage of that. Seems they
> never finished this.

This particular option exists purely to allow *printers* that support JPEG
images tio be supplied raw JPEG images. GDI doesnt decode JPEGs supplied at
all like this, it relies on device suport :- see the documentation for
ExtEscape to see how to test for JPEG support.

ne...@rtrussell.co.uk

unread,
Nov 23, 2006, 9:47:36 AM11/23/06
to
Grzegorz Wróbel wrote:
> Full path is not that trouble, however I can't get OleLoadPicturePath
> working.

It works just fine for me: I use it all the time! Did you remember to
convert the pathname to Unicode (MultiByteToWideChar)?

Grzegorz Wróbel

unread,
Nov 23, 2006, 10:22:18 AM11/23/06
to
ne...@rtrussell.co.uk wrote:
> Grzegorz Wróbel wrote:
>> Full path is not that trouble, however I can't get OleLoadPicturePath
>> working.
>
> It works just fine for me: I use it all the time! Did you remember to
> convert the pathname to Unicode (MultiByteToWideChar)?

Yes, I did provided full path and converted it to wide character string.
The problem might be that I'm not sure what to pass as first parameter.
I left NULL as I saw on some example, the call crashed.

ne...@rtrussell.co.uk

unread,
Nov 23, 2006, 1:26:09 PM11/23/06
to
Grzegorz Wróbel wrote:
> Yes, I did provided full path and converted it to wide character string.
> The problem might be that I'm not sure what to pass as first parameter.
> I left NULL as I saw on some example, the call crashed.

Do you mean the second parameter (the first parameter is the pathname)?
I've always passed NULL as the second parameter and it doesn't crash
here:

OleLoadPicturePath(wpath,NULL,NULL,NULL,IID_IPicture,(LPVOID*)&ipic);

Grzegorz Wróbel

unread,
Nov 23, 2006, 2:35:43 PM11/23/06
to
ne...@rtrussell.co.uk wrote:
> Grzegorz Wróbel wrote:
>> Yes, I did provided full path and converted it to wide character string.
>> The problem might be that I'm not sure what to pass as first parameter.
>> I left NULL as I saw on some example, the call crashed.
>
> Do you mean the second parameter (the first parameter is the pathname)?
> I've always passed NULL as the second parameter and it doesn't crash
> here:
>
> OleLoadPicturePath(wpath,NULL,NULL,NULL,IID_IPicture,(LPVOID*)&ipic);

Yes, of course I meant second. Maybe it was something wrong with the
path or I forgot to get adress of &ipicture). I try to compile version
with OleLoadPicturePath as well, should a bit shorter.

Now, the main problem I have with these methods, either OleLoadPicture()
or OleLoadPicturePath() is that I really want to obtain bitmap bits in
RGB format. I can put the HBITMAP into DC and call GetDIBits, but if the
DC is 16 or 8bit this will result in quality loss.

Lucian Wischik

unread,
Nov 23, 2006, 2:42:04 PM11/23/06
to
Grzegorz Wróbel </dev/nu...@localhost.localdomain> wrote:
>Since I am really interested in obtaining bits not HBITMAP, any method
>that requires using a DC is not perfect. In my code I put the bitmap
>into DC and call GetDIBits. The problem will be if the DC is 16 or 8
>bits. This will hit the quality. I quess using CreateDIBSection and
>BitBlting trough display's compatible DC as you do it will have the same
>result.

I don't think it will. If you create a 24bpp DIBSection then it'll be
24bpp regardless of the current display mode. To obtain the raw bits,
use either the *ppvBits that was given back to you by
CreateDIBSection, or use DIBSECTION dibs;
GetObject(hbm,&dibs,sizeof(dibs)); dibs.whatever.ppvBits.

--
Lucian

Grzegorz Wróbel

unread,
Nov 23, 2006, 3:15:06 PM11/23/06
to
Lucian Wischik wrote:
> Grzegorz Wróbel </dev/nu...@localhost.localdomain> wrote:
>> Since I am really interested in obtaining bits not HBITMAP, any method
>> that requires using a DC is not perfect. In my code I put the bitmap
>> into DC and call GetDIBits. The problem will be if the DC is 16 or 8
>> bits. This will hit the quality. I quess using CreateDIBSection and
>> BitBlting trough display's compatible DC as you do it will have the same
>> result.
>
> I don't think it will. If you create a 24bpp DIBSection then it'll be
> 24bpp regardless of the current display mode. To obtain the raw bits,
> use either the *ppvBits that was given back to you by
> CreateDIBSection,

When you blitblt from one hbitmap to another then during this operation
colordepth will be reduced to current DC's. Sure I'll get bits in 24bpp
data format, but if the DC was 8bit it won't be there more than 256
unique colors there.

> or use DIBSECTION dibs;
> GetObject(hbm,&dibs,sizeof(dibs)); dibs.whatever.ppvBits.

I tried this and suprisingly it was 8bits in 8bpp mode, even though HDC
was never used explicitly since I copied hbitmap from IPicture using
CopyImage().

Grzegorz Wróbel

unread,
Nov 23, 2006, 3:54:20 PM11/23/06
to
Grzegorz Wróbel wrote:
> ne...@rtrussell.co.uk wrote:
>> OleLoadPicturePath(wpath,NULL,NULL,NULL,IID_IPicture,(LPVOID*)&ipic);
>
...

> path or I forgot to get adress of &ipicture). I try to compile version
> with OleLoadPicturePath as well, should a bit shorter.

It works now - 6 lines of code now instead of 19 and 3 variables less :)

ne...@rtrussell.co.uk

unread,
Nov 23, 2006, 4:47:15 PM11/23/06
to
Grzegorz Wróbel wrote:
> When you blitblt from one hbitmap to another then during this operation
> colordepth will be reduced to current DC's. Sure I'll get bits in 24bpp
> data format, but if the DC was 8bit it won't be there more than 256
> unique colors there.

Indeed: it's a shortcoming of Windows that I've never been able to
overcome. As you say, even if there is no explicit reference to any DC
the current display settings limit the color depth you end up with.
It's completely insane, and if anybody knows a way to overcome it
(short of bypassing the API completely) I would be very interested.
It's hard to understand the processes going on 'under the hood' that
lead to this behavior.

Fortunately it's less of a problem than it once was because display
color depths of fewer than 24 bits are becoming increasingly rare.

Grzegorz Wróbel

unread,
Nov 24, 2006, 6:46:28 AM11/24/06
to
ne...@rtrussell.co.uk wrote:
> Grzegorz Wróbel wrote:
>> When you blitblt from one hbitmap to another then during this operation
>> colordepth will be reduced to current DC's. Sure I'll get bits in 24bpp
>> data format, but if the DC was 8bit it won't be there more than 256
>> unique colors there.
>
> Indeed: it's a shortcoming of Windows that I've never been able to
> overcome. As you say, even if there is no explicit reference to any DC
> the current display settings limit the color depth you end up with.
> It's completely insane, and if anybody knows a way to overcome it
> (short of bypassing the API completely) I would be very interested.
> It's hard to understand the processes going on 'under the hood' that
> lead to this behavior.

I think it's not possible if you're using GDI object. I was thinking
once about creating 32bit memory DC and perform operatons in memory
using these DC, but a) it's not easy to create such DC without having an
actual device that supports it b) since some functions use current
display's colordepth implicitly this probably wouldn't work anyway.

>
> Fortunately it's less of a problem than it once was because display
> color depths of fewer than 24 bits are becoming increasingly rare.

Indeed, and the 8bit mode is officially not supported anymore (though
one can still change to this mode using ChangeDisplaySettings() API).

Jim Barry

unread,
Nov 24, 2006, 2:14:10 PM11/24/06
to
Grzegorz Wróbel wrote:
> Now, the main problem I have with these methods, either
> OleLoadPicture() or OleLoadPicturePath() is that I really want to
> obtain bitmap bits in RGB format.

The bitmap should already be a 24-bit DIB-section. Call GetObject to fill a DIBSECTION structure, then you can access the image data via dsBm.bmBits.

--
Jim Barry, MVP (Windows SDK)

ne...@rtrussell.co.uk

unread,
Nov 24, 2006, 3:27:24 PM11/24/06
to
Jim Barry wrote:
> The bitmap should already be a 24-bit DIB-section. Call GetObject to fill a DIBSECTION structure, then you can access the image data via dsBm.bmBits.

You've not actually tried it, have you?! It would be really great if
it worked, but unfortunately it doesn't. If you change your display
settings to 16bpp, for example, the object returned by GetObject is a
16-bits DIBSECTION, not 24-bits! This is despite there being no
reference to a DC or a device at all. If you can find a way to make it
work I would love to know, but failing that I would really like an
explanation of why Windows works this apparently crazy way. What have
the display settings got to do with transferring a JPEG from a file to
a DIBSECTION?

Jim Barry

unread,
Nov 24, 2006, 8:50:25 PM11/24/06
to
ne...@rtrussell.co.uk wrote:
> You've not actually tried it, have you?!

Guilty as charged. Actually, I did try it, but didn't think to check it with a 16-bit display setting. I hadn't counted on Windows capping the colour depth to that of the current display mode. Now that's what I call a premature optimisation :-(

I've been through the mill with JPEG stuff before (in particular, the lack of any Windows facility for saving JPEGs) and ended up using the IJG library. Interestingly, the code behind OleLoadPicture is based on the IJG library, too.

Jean

unread,
Nov 27, 2006, 3:29:13 PM11/27/06
to
The Independent JPEG Group (IJG) provides a free and open source code
library for compressing and decompressing JPEG images.

The library is written in C, and is designed to be portable between many
compilers and platforms.

The distribution includes the JPEG library proper, plus two application
programs ("cjpeg" and "djpeg") which use the library to convert JPEG
files to and from some other popular image formats.

ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/jpegsr6.zip

With best regards

____
Jean

ne...@rtrussell.co.uk

unread,
Nov 27, 2006, 4:26:38 PM11/27/06
to
Jean wrote:
> The Independent JPEG Group (IJG) provides a free and open source code
> library for compressing and decompressing JPEG images.
>
> The library is written in C, and is designed to be portable between many
> compilers and platforms.

Is it available as a pre-compiled DLL? That would be really useful (I
mainly program in a language which cannot make use of C source code nor
link to object modules).

Grzegorz Wróbel

unread,
Nov 28, 2006, 11:19:20 AM11/28/06
to

You could probably build yourself a dll from that code that exports you
the functions you need.

0 new messages