|
I found this article very helpful in explaining how to use the OLE features of Windows to display a JPG image. Some of us have old projects which have to be maintained using old tools, like the Watcom compiler for example, which doesn't support MFC.
The rude commenter who suggested using a Microsoft class missed the whole point of the article. Referring to the quality of the code, which the rude commenter also disparaged, it looks good to me except for the use of the global static, which I suppose was done to simplify the code for demonstration purposes, not exactly a big flaw, and is easy enough to correct if the usage requires it!
Anyway, thanks!
|
|
|
|
|
|
Just want to say - Its Highness "C"!!
Thank you for the wonderful code - made my day!
|
|
|
|
|
Needs complete project to show it working.
|
|
|
|
|
I am new to windows programming and I am developing, at the moment my first windows application and I have the following concerns.
-how does one link a library to a project using microsoft VCC++ compiler.
-I tried using the display image example program shown below ,but it did not work at all.
What does the writer mean by coinnitialize().
The program has thee function CloseImage(), why the reference to CloseGraphic(),
The compiler complained that render() is not a member of IPicture.It also did not recognise lpVtbl. I really and urgently need assistance.
Is there some other simpler method of rendering images.
I hope to hear from someone soon.
#include "windows.h"
#include "ocidl.h"
#include "olectl.h"
typedef struct tagImgInfo {
IPicture *Ipic;
SIZE sizeInHiMetric;
SIZE sizeInPix;
char *Path;
} IMG_INFO;
static IMG_INFO ImageInfo;
void *OpenGraphic(char *name)
{
IPicture *Ipic = NULL;
SIZE sizeInHiMetric,sizeInPix;
const int HIMETRIC_PER_INCH = 2540;
HDC hDCScreen = GetDC(NULL);
HRESULT hr;
int nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
int nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
unsigned short OlePathName[512];
ReleaseDC(NULL,hDCScreen);
mbstowcs(OlePathName,name,strlen(name)+1);
hr = OleLoadPicturePath(OlePathName,
NULL,
0,
0,
&IID_IPicture,
(void *)(&Ipic));
if (hr)
return 0;
if (Ipic) {
// get width and height of picture
hr = Ipic->lpVtbl->get_Width(Ipic,&sizeInHiMetric.cx);
if (!SUCCEEDED(hr))
goto err;
Ipic->lpVtbl->get_Height(Ipic,&sizeInHiMetric.cy);
if (!SUCCEEDED(hr))
goto err;
// convert himetric to pixels
sizeInPix.cx = (nPixelsPerInchX * sizeInHiMetric.cx +
HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
sizeInPix.cy = (nPixelsPerInchY * sizeInHiMetric.cy +
HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
ImageInfo.sizeInPix = sizeInPix;
ImageInfo.sizeInHiMetric = sizeInHiMetric;
ImageInfo.Ipic = Ipic;
ImageInfo.Path = name;
return Ipic;
}
err:
return 0;
}
void DisplayGraphic(HWND hwnd,HDC pDC)
{
IPicture *Ipic = ImageInfo.Ipic;
DWORD dwAttr = 0;
HBITMAP Bmp,BmpOld;
RECT rc;
HRESULT hr;
HPALETTE pPalMemOld;
if (Ipic != NULL)
{
// get palette
OLE_HANDLE hPal = 0;
HPALETTE hPalOld=NULL,hPalMemOld=NULL;
hr = Ipic->lpVtbl->get_hPal(Ipic,&hPal);
if (!SUCCEEDED(hr))
return;
if (hPal != 0)
{
hPalOld = SelectPalette(pDC,(HPALETTE)hPal,FALSE);
RealizePalette(pDC);
}
// Fit the image to the size of the client area. Change this
// For more sophisticated scaling
GetClientRect(hwnd,&rc);
// transparent?
if (SUCCEEDED(Ipic->lpVtbl->get_Attributes(Ipic,&dwAttr)) ||
(dwAttr & PICTURE_TRANSPARENT))
{
// use an off-screen DC to prevent flickering
HDC MemDC = CreateCompatibleDC(pDC);
Bmp =
CreateCompatibleBitmap(pDC,ImageInfo.sizeInPix.cx,ImageInfo.sizeInPix.cy);
BmpOld = SelectObject(MemDC,Bmp);
pPalMemOld = NULL;
if (hPal != 0)
{
hPalMemOld = SelectPalette(MemDC,(HPALETTE)hPal, FALSE);
RealizePalette(MemDC);
}
/* Use this to show the left corner
rc.left = rc.top = 0;
rc.right = ImageInfo.sizeInPix.cx;
rc.bottom = ImageInfo.sizeInPix.cy;
*/
// display picture using IPicture::Render
hr = Ipic->lpVtbl->Render(Ipic,MemDC,
0,
0,
rc.right,
rc.bottom,
0,
ImageInfo.sizeInHiMetric.cy,
ImageInfo.sizeInHiMetric.cx,
-ImageInfo.sizeInHiMetric.cy,
&rc);
BitBlt(pDC,0, 0, ImageInfo.sizeInPix.cx,
ImageInfo.sizeInPix.cy,
MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC,BmpOld);
if (pPalMemOld) SelectPalette(MemDC,pPalMemOld, FALSE);
DeleteObject(Bmp);
DeleteDC(MemDC);
}
else
{
// display picture using IPicture::Render
Ipic->lpVtbl->Render(Ipic,pDC,
0,
0,
rc.right,
rc.bottom,
0,
ImageInfo.sizeInHiMetric.cy,
ImageInfo.sizeInHiMetric.cx,
-ImageInfo.sizeInHiMetric.cy,
&rc);
}
if (hPalOld != NULL) SelectPalette(pDC,hPalOld, FALSE);
if (hPal) DeleteObject((HPALETTE)hPal);
}
}
void CloseImage(void *Ipict)
{
IPicture *ip = (IPicture *)Ipict;
if (ip == NULL)
ip = ImageInfo.Ipic;
if (ip == NULL)
return;
ip->lpVtbl->Release(ip);
memset(&ImageInfo,0,sizeof(ImageInfo));
}
|
|
|
|
|
A piece of code from the DisplayGraphic function:
<br />
hr = Ipic->lpVtbl->Render(Ipic,MemDC,<br />
0,<br />
0,<br />
rc.right,<br />
rc.bottom,<br />
0,<br />
ImageInfo.sizeInHiMetric.cy,<br />
ImageInfo.sizeInHiMetric.cx,<br />
-ImageInfo.sizeInHiMetric.cy,<br />
&rc);<br />
By this code it should stretch the image to the size of the window but it draws only to the area of image size. So the size is the same but it is stretched and you can't see the whole image, if the window isn't exactly the size of the image. I replaced it with:
<br />
hr = Ipic->lpVtbl->Render(Ipic,MemDC,<br />
0,<br />
0,<br />
ImageInfo.sizeInPix.cx,<br />
ImageInfo.sizeInPix.cy,<br />
0,<br />
ImageInfo.sizeInHiMetric.cy,<br />
ImageInfo.sizeInHiMetric.cx,<br />
-ImageInfo.sizeInHiMetric.cy,<br />
&rc);<br />
Now it is not strecthed and the area is still the size of the image.
-- modified at 7:24 Friday 17th February, 2006
|
|
|
|
|
This is very important! I loaded a black square before. After I used the code here, I got the right picture.
Thanks.
|
|
|
|
|
170k is that with or without the debug info
|
|
|
|
|
Any idea, how can I ROTATE 90, 180 etc using an IPicture object, once it is loaded and showing on screen...
Thanks
Alex
|
|
|
|
|
The size of the binary is not a difference between VC++ compiler and ur compiler. in VC++ if you remove all unwanted libs that are linked together will bring the size of the binary to bare minimum.
|
|
|
|
|
I don't understand the critics. The present version worked immediately, fast, clean and simple ! The resulting exe is just 28 KB in size and displays the image correctly.
Copied the code from the HTML page directly into a .C-file in MS Visual Studio, created a simple SDI main program, moved the function calls and typedef into a header file and i was ready to show the images....
Good job, Jacob
Rob
|
|
|
|
|
Please post a complete workable project, not just the functions.
|
|
|
|
|
I tried in MFC Project in the following code : But, i did not get proper solution.I have no error & warning .
void CImageDlg::OpenGraphicA(char *name1)
{
IPicture *Ipic = NULL;
SIZE sizeInHiMetric,sizeInPix;
const int HIMETRIC_PER_INCH = 2540;
HDC hDCScreen = ::GetDC(m_hWnd);
HRESULT hr;
int nPixelsPerInchX = ::GetDeviceCaps(hDCScreen, LOGPIXELSX);
int nPixelsPerInchY = ::GetDeviceCaps(hDCScreen, LOGPIXELSY);
unsigned short OlePathName[512];
::ReleaseDC(NULL,hDCScreen);
mbstowcs(OlePathName,name1,strlen(name1)+1);
hr = ::OleLoadPicturePath(OlePathName,
NULL,
0,
0,
IID_IPicture,
(void **)(&Ipic));
if (hr)
MessageBox("Error");
if (Ipic) {
// get width and height of picture
hr = Ipic->get_Width(&sizeInHiMetric.cx);
if (!SUCCEEDED(hr))
goto err;
Ipic->get_Height(&sizeInHiMetric.cy);
if (!SUCCEEDED(hr))
goto err;
// convert himetric to pixels
sizeInPix.cx = (nPixelsPerInchX * sizeInHiMetric.cx +
HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
sizeInPix.cy = (nPixelsPerInchY * sizeInHiMetric.cy +
HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
ImageInfo.sizeInPix = sizeInPix;
ImageInfo.sizeInHiMetric = sizeInHiMetric;
ImageInfo.Ipic = Ipic;
ImageInfo.Path = name1;
// return Ipic;
}
err:
MessageBox("Error");
// return 0;
}
void CImageDlg::DisplayGraphicA(HWND hwnd,HDC pDC)
{
IPicture *Ipic = ImageInfo.Ipic;
DWORD dwAttr = 0;
HBITMAP Bmp,BmpOld;
RECT rc;
HRESULT hr;
HPALETTE pPalMemOld;
if (Ipic != NULL)
{
// get palette
OLE_HANDLE hPal = 0;
HPALETTE hPalOld=NULL,hPalMemOld=NULL;
hr = Ipic->get_hPal(&hPal);
if (!SUCCEEDED(hr))
return;
if (hPal != 0)
{
hPalOld = ::SelectPalette(pDC,(HPALETTE)hPal,FALSE);
::RealizePalette(pDC);
}
// Fit the image to the size of the client area. Change this
// For more sophisticated scaling
::GetClientRect(hwnd,&rc);
// transparent?
if (SUCCEEDED(Ipic->get_Attributes(&dwAttr)) ||
(dwAttr & PICTURE_TRANSPARENT))
{
// use an off-screen DC to prevent flickering
HDC MemDC = CreateCompatibleDC(pDC);
Bmp = CreateCompatibleBitmap(pDC,ImageInfo.sizeInPix.cx,ImageInfo.sizeInPix.cy);
BmpOld = (HBITMAP)SelectObject(MemDC,Bmp);
pPalMemOld = NULL;
if (hPal != 0)
{
hPalMemOld = SelectPalette(MemDC,(HPALETTE)hPal, FALSE);
RealizePalette(MemDC);
}
/* Use this to show the left corner
rc.left = rc.top = 0;
rc.right = ImageInfo.sizeInPix.cx;
rc.bottom = ImageInfo.sizeInPix.cy;
*/
// display picture using IPicture::Render
hr = Ipic->Render(MemDC,
0,
0,
rc.right,
rc.bottom,
0,
ImageInfo.sizeInHiMetric.cy,
ImageInfo.sizeInHiMetric.cx,
-ImageInfo.sizeInHiMetric.cy,
&rc);
BitBlt(pDC,0, 0, ImageInfo.sizeInPix.cx,
ImageInfo.sizeInPix.cy,
MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC,BmpOld);
if (pPalMemOld) SelectPalette(MemDC,pPalMemOld, FALSE);
DeleteObject(Bmp);
DeleteDC(MemDC);
}
else
{
// display picture using IPicture::Render
Ipic->Render(pDC,
0,
0,
rc.right,
rc.bottom,
0,
ImageInfo.sizeInHiMetric.cy,
ImageInfo.sizeInHiMetric.cx,
-ImageInfo.sizeInHiMetric.cy,
&rc);
}
if (hPalOld != NULL) SelectPalette(pDC,hPalOld, FALSE);
if (hPal) DeleteObject((HPALETTE)hPal);
}
}
|
|
|
|
|
What causes this error?
'Render' : is not a member of 'IPicture'
My includes are olectl.h,oleaut.h,ocidl.h and ole32.lib, olepro32.lib
|
|
|
|
|
Well I linked with
ole32.lib oleaut32.lib uuid.lib
and worked fine when in 16 bit color mode, but with 256 color after twice openfiles the system hang-up...
But if I comment the line:
if (hPal) DeleteObject(hPal);
the thing work fine, but this is wrong. It's not?
Someone can help?
|
|
|
|
|
Seen on MS doc: "A picture object created using OleLoadPicture always has ownership of its internal resources (fOwn==TRUE is implied)."
OleLoadPicturePath (used by this code) works the same way.
Then, if you read the doc of IPicture::get_hPal you find:
"Notes to Callers
If the picture object has ownership of the picture, it also has ownership of the palette and will destroy it when the object is itself destroyed. Otherwise the caller owns the palette. The fOwn parameter to OleCreatePictureIndirect determines ownership. OleLoadPicture sets fOwn to TRUE to indicate that the picture object owns the palette."
The result is that there should be no call to DeleteObject(hPal) (so you were right to remove this call).
Otherwise, even with bugs, I find this code useful as an example to use IPalette. I thank the author for that.
|
|
|
|
|
Your statement about LCC being a better compiler are false. VC++ is by FAR a better compiler with a lot of optimizations that LCC does not have. I'm not saying VC++ is perfect because it isn't, but it's the best we have for windows at the moment.
Your comments about the size of the executable are ignorant. Maybe if you knew how to use both LCC and VC++ you would understand why the default LCC executable is smaller then the default VC++ executable.
Thirdly, this will not load JPEG images on windows 95/98/NT since this wasn't added until ME/2K to Windows. When designing source code for people to use it would be best if you stated the limitations, which could be found by reading MSDN. If you look at the good projects on this site they nearly always work across all the Windows Systems.
I hope you will use this message constructively to improve your programming skills.
|
|
|
|
|
"I'm not saying VC++ is perfect because it isn't, but it's the best we have for windows at the moment."
Haha, funny. I hope you're not seriuos.
Every test shows that Intel's C compiler is by far the best C and C++ compiler for Windows.
And I know a couple of compilers that produce smaller executables than VC++, and even if I haven't tried LCC I wouldn't be supprise if it produces smaller files than VC++.
But the real issue here isn't if one compiler produces smaller files, the important thing is that C is smaller and faster than C++, and that's why this is a great article.
|
|
|
|
|
Bullshit!
lcc-win32 is great!
and the code run fine in my Win95...
|
|
|
|
|
really to hell with VC and .NET architecture,
LCC, and GCC rock, who the hell needs the stupid additional dozzens of code generated by dumb head VC. Every developer tries to have minimal binaries so that they are easily distributable.
You write what you think, but do not care about the effort of the person who is giving you a free source, if it is not useful to you and you cant write two words of appreciation, then goto hell and dont join the discussion thread.
Author has done a great job, and was tryign to differentiate between the minimum possible output of the final executable. Did he force you to download and/or discuss his resources ?
Quoting everything comes to your stupid brain, and then saying "I hope you will use this message constructively to improve your programming skills." does not heal up the wounds . What do yo uknow abotu the strfucture of VC compiler, tell me streight, I would like to have debate on it 'WITH YOU'.
Now, when directX has also been made embedable with c++ applciations and made available opensource in the form of libraries and headers [so that developers dont have to ship the shared DLLs], you will come to say, this is not workign properly as Microsoft directX Dynamic Linked Libraries.
Few questions for you,
1.how many technologies you know, especially compilers ?
2.can you compile pure windows API source on Linux ??????I CAN.
3.Did you ever create a compiler or even an interpreter or IDE ?
I am sure all will be
1. No
2. No
3. No
Then why the heck you are criticizing a person who comes with a very good source? although he forgot to mention the platform compatibility.
btw nice job Mr.Author.
|
|
|
|
|
Apart from the other valid complaints about your source code, I find it an absolute waste to tell you the truth. It's neither simple nor is it powerful by all means nor is it beautiful -- yet you stated that it would be all of the above. Let me propose an alternative approach: if I ever needed a jpg/gif/bmp/png/... displayed I'd merely misuse a listview control. Without headers, possibly even without a frame and without any items in it. To display the image, you only need to load it as a background image and resize the control accordingly. Probably no more than 5 lines of code....
Other than that: Thanks for acting as a living example for the inferiority of open source software.
|
|
|
|
|
Dear Anonymous:
Thanks for your contribution.
It is really a good idea.
I tried it, and it works without problems.
I have to confess that I did not learnt all the windows API by heart and that I did not knew that a listview control will display an image, incorporating the code I presented in the example of course. If you do not do a CoInitialize() before, the listview will not display anything, so I deduce that it is using the same IPicture interface.
As to your "Thanks for acting as a living example of the inferiority of open source software" just this: I try to share my code with others. I dare even to publish it and to ask my fellow programmers for his/her opinions, risking meeting people like you.
Sincerely
Jacob Navia
|
|
|
|
|
Jacob Navia wrote:
As to your "Thanks for acting as a living example of the inferiority of open source software" just this: I try to share my code with others. I dare even to publish it and to ask my fellow programmers for his/her opinions, risking meeting people like you.
Good Response, Jacob!
Notice, there is not even a name attached to the dissing message either.
Certainly Open Source can provide some less-than-optimum code, but the beauty of it is IT CAN BE FIXED. And IT IS REVIEWED. Even by persons as ill-mannered as the original poster. And you don't need to buy the next version to get the bug fixes.
Rufus
|
|
|
|
|
I have written a 4k intro in Visual C++ which did a whole lot more than this. It's got a softsynth, and uses OpenGL for graphics.
http://www.pouet.net/prod.php?which=5199
|
|
|
|
|
I applaud your decision to contribute your first article to CodeProject. However, the code you submitted does not work, and shows that you could not have possibly tested the code before you submitted it. Moreover, some of your coding practices would be totally unacceptable in any production environment.
For starters, the function ::OleLoadPicturePath() returns a pointer to the IPicture interface. This object is initialized by ::OleLoadPicturePath() , complete with the handle of the bitmap. However, in your code, you never reference the get_Handle method, so the bitmap never gets displayed.
The code itself contains several questionable items. First, the ImageInfo variable is a global, so use of the code for multiple images is out of the question.
Second, the call to ::OleLoadPicturePath() is incorrect. Instead of
HRESULT hr = OleLoadPicturePath(OlePathName,
NULL,
0,
0,
&IID_IPicture,
(void *)(&Ipic));
the correct parameters are:
HRESULT hr = OleLoadPicturePath(OlePathName,
NULL,
0,
0,
IID_IPicture,
(void **) (&Ipic));
Third, the function
void DisplayGraphic(HWND hwnd,HDC *pDC)
requires passing a pointer to a HDC. This is not only inconsistent with general Windows API usage, it is inconsistent within the code presented in the article. There are many places in the code which use this pointer, for example:
hPalOld = SelectPalette(pDC,hPal,FALSE);
Note that the function SelectPalette requires a HDC, not a pointer to a HDC.
Fourth, when the methods of the IPicture (Ipic) object are invoked, they are called via reference to "lpVtbl". For example, the Render method is called like this:
hr = Ipic->lpVtbl->Render(Ipic,MemDC,...
This syntax is incorrect in Microsoft VC++. In order to compile correctly, the code must be written as:
hr = Ipic->Render(MemDC,...
To summarize, you make claims about how small this code is when compiled, but it is hard to see how it could ever work correctly. I know nothing about the lcc-win32 compiler, but for most of the people on CodeProject, it is irrelevant, no matter how good it is. If you want to post more articles on CodeProject, my suggestion would be to test your code with MS VC++.
|
|
|
|
|