Author Topic: IImgCtx demystified  (Read 597 times)

Biterider

  • Moderator
  • Member
  • *****
  • Posts: 383
  • ObjAsm32 + ObjAsm64 = ObjAsm
    • ObjAsm
IImgCtx demystified
« on: June 27, 2019, 07:17:39 AM »
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

Biterider

  • Moderator
  • Member
  • *****
  • Posts: 383
  • ObjAsm32 + ObjAsm64 = ObjAsm
    • ObjAsm
An addition to IImgCtx
« Reply #1 on: July 06, 2019, 11:11:58 PM »
Hi
The interface has an additional method called Tile. It basically works like the drawing method, except that the image is tiled depending on the specified parameters.

These are:
hDC: The target device context.
pOrgPoint: Pointer to the origin POINT on the tile where the tiling process begins.
pClipRect: Pointer to the destination RECT.
pSize: Pointer to a SIZE_ structure with the dimensions of the tile. Regardless of the sizeof the original image, it is stretched to fit that size.

Attached a short demo showing this method in action. This is a variation of the previous demo.

The ObjAsm Image object is now expanded by two new methods: Tile and AlphaTile.

Biterider

HSE

  • Member
  • *****
  • Posts: 1130
  • <AMD>< 7-32>
Re: IImgCtx demystified
« Reply #2 on: July 07, 2019, 04:42:10 AM »
Hi Biterider!

Building example in 32bit, no images here :biggrin:

If working, this have to show the image?
Code: [Select]
  OCall [xsi].Img1::Image.GetCompatibleBmp, hDC
mov hBMP, eax
  DbgBmp hBMP
DebugCenter say communication failed due to low system resources.

Manual:
Quote
Bitmaps
 DbgGUID hBmp, "DestWnd": displays the bitmap referred to by hBmp (only possible using DebugCenter).

Biterider

  • Moderator
  • Member
  • *****
  • Posts: 383
  • ObjAsm32 + ObjAsm64 = ObjAsm
    • ObjAsm
Re: IImgCtx demystified
« Reply #3 on: July 07, 2019, 03:23:54 PM »
Hi HSE
Quote
DbgGUID hBmp, "DestWnd": displays the bitmap referred to by hBmp (only possible using DebugCenter).
Here, I should have written DbgBmp  :rolleyes:  It is corrected now.

I tested the following code on the example of the first post
Code: [Select]
  OCall [xsi].Img1::Image.GetCompatibleBmp, hDC
  DbgBmp xax
and get the image on DC.

I attach the current "Image" code to sync with you. Maybe you are getting problems because of the "low system resources".
Do the posted exes work on your system?

Biterider
« Last Edit: July 07, 2019, 07:47:30 PM by Biterider »

HSE

  • Member
  • *****
  • Posts: 1130
  • <AMD>< 7-32>
Re: IImgCtx demystified
« Reply #4 on: July 08, 2019, 05:48:58 AM »
Hi Biterider!

Do the posted exes work on your system?
Perfectly  :thup:

My bulding in 7-64 bit don't show nothing either  :thdn:
DebugCenter show a black window.

HSE


Biterider

  • Moderator
  • Member
  • *****
  • Posts: 383
  • ObjAsm32 + ObjAsm64 = ObjAsm
    • ObjAsm
Re: IImgCtx demystified
« Reply #5 on: July 08, 2019, 04:41:19 PM »
Hi HSE
I have a guess.  :icon_idea:
It may be possible that the constant called IMAGE is not defined. I added it to my Resource.h file and commented it out in the .rc file.

Code: [Select]
#define IMAGE 2110
Biterider


HSE

  • Member
  • *****
  • Posts: 1130
  • <AMD>< 7-32>
Re: IImgCtx demystified
« Reply #6 on: July 09, 2019, 03:14:44 AM »
Hi Biterider!

 :thumbsup: Yes is that.

Thanks. HSE