Hi
I think everyone once wished to have a piece of software to decode the most common graphics formats like jpg, png, gif etc. without having big problems. As we all probably know, there is the GDI+ way that we have seen here in the forum several times, the LoadImage API, IPicture and others. All of these have their own limitations and pitfalls.
IImgCtx also falls into this category, until today.
The
IImgCtx COM interface has been mentioned more than 15 years ago in some internet publications (
https://www.codeproject.com/Articles/7065/An-Image-Decoder-Based-on-IImgCtx,
https://www.codeproject.com/Articles/11234/Win32-Image-Decoder-in-C,
https://stackoverflow.com/questions/2650707/how-do-i-use-iimgctx-to-get-load-an-image-with-an-alpha-channel,
http://masm32.com/board/index.php?topic=309.0,
http://www.smorgasbordet.com/pellesc/sample_imgctx.htm),
but due to the lack of Microsoft documentation, it was rarely used. Only the header file was officially published some years ago.
I decided to find out by myself how the interface works and at last make better use of it.
I will not repeat what has already been published. I refer to the above links to find out what is already known.
The core functionality resides in two methods,
IImgCtx.Load and
IImgCtx.Draw.
IImgCtx.Load is called to decode the graphic information packed in wide range of formats (jpg, tif, gif, bmp, etc.). It should be noted here that as parameters it accepts URL wide strings (<scheme>:<scheme-specific-part>), which opens up many interesting possibilities, such as opening web-, local- or resource-files.
Because being an asynchronous method, there are two ways to monitor the progress of the operation. A polling method and a callback procedure are provided.
Polling is typically used when a fast execution of the operation is expected. It is implemented by the
IImgCtx.GetStateInfo method.
The callback usage must be set up using the
IImgCtx.SetCallback and
IImgCtx.SelectChanges methods.
The
IImgCtx.SetCallback method receives the callback procedure address and an additional value, which is later passed as the second parameter to the callback. This is a user-defined value (pPrivate) and can be used for any purpose.
The
IImgCtx.SelectChanges method determines which changes trigger the callback call. In most cases, the finalization of the loading process is of interest, so IMGCHG_COMPLETE is passed as argument.
You would be tempted to use a native synchronization object like
WaitForSingleObject to avoid expensive polling, but it will not work. In this case, our application will block. The reason is the way the code was designed. If we put the calling thread in a wait state using
WaitForSingleObject, the callback is never executed because it uses exactly the same thread. How does it work then?
I noticed that a new unexpected message appeared on my window message pump. It caught my attention because it was in a rarely used range. The ID is
WM_APPSTR + 00EAh (0xC00EA) and only appears when the callback is triggered. The wParam and lParam parameters that accompany the message are both NULL. That means that the message is used exclusively to signal the callback invocation.
This situation can also be used to intercept this message without having to place any code in the callback, where a mere ret instruction would be enough.
The interface code probably installs a hook on the message pump to get this notification and trigger the callback mechanism. It fills the two arguments which are handed over to the callback. One is the user defined value mentioned earlier (second parameter) and the second is a pointer to a
CDwnCtx structure, which is completely undocumented.
Unfortunately, the
IImgCtx implementation does not allow us to access to the raw image information. It provides the
IImgCtx.Draw method that can be used to build a bitmap. The interesting property of this method is that it copies the alpha values of the source image. That way, using an API like
AlphaBlend, we can use transparency, too.
Do not try to use the
IImgCtx.StrechtBlt interface method. Until now (2019) it is not implemented. It returns 0x80004002.
I built an ObjAsm object which uses the previously described functionality and a demo that shows a very good performance using alpha drawing and halftone stretching.
Attached are the sources and the demo application.
Biterider