Ureader.com  
Microsoft software help and Community
   home   |   control panel login   |   archive   |  
 
platform
active.directory
adsi
adsi.iis-admin
base
com_ole
complus_mts
component_svcs
database
directx
gdi
graphics_mm
internet.client
internet.server
internet.server.isapi-dev
localization
mapi
messaging
msi
mslayerforunicode
multimedia
networking
networking.ipv6
sdk_install
security
shell
telephony.tapi_2
telephony.tapi_3
telephony.tsp
telephony.wte
tools
ui
ui_shell
win_base_svcs
win16
  
 
date: Tue, 1 Apr 2008 09:03:02 -0700,    group: microsoft.public.platformsdk.shell        back       


Windows XP thumbnail shell extension   
I'm working on a thumbnail extractor shell extension for a custom file type 
(Windows XP only, i.e., we don't have Vista boxes and can't use the new 
thumbnail providers).  For testing, I've registered an extension for a bogus 
file type and created a file with that type, but the test files are just 
renamed .bmp files.  The basic mechanism in my prototype seems to work OK, 
except that the test thumbnail that I extract from the .bmp file and that the 
shell displays appears to be somewhat lower resolution than the thumbnail 
that the .bmp file type's own thumbnail extractor (which doesn't actually 
appear to be registered as an actual "ShellEx" itself) gets from the same 
file.

In theory, the thumbnail for my bogus file type should look the same as the 
thrumbnail produced by the .bmp file since it's actually pulling the bitmap 
from the same data.  My extractor prototype appears to produce a thumbnail of 
the correct size and same scale, and has the same colors, but it appears 
somewhat "coarser" or "splotchier" than the thumbnail the shell produces for 
the .bmp.

The preview pane in the "Details" view mode was a different story -- the 
preview produced by my prototype was stretched very tall, even though I was 
using the size passed in by GetLocation to scale it.

As an additional test, I wired up the "tridentimageextractor" built-in 
extractor, and it appeared to also produce a somewhat lower resolution 
thumbnail than whatever is actually handling .bmp files these days.  (The 
built-in didn't have the same vertical distortion in the Details mode 
preview, however.)

Finally, I created a test .bmp file at exactly 96 x 96 resolution, and when 
renamed, the thumbnails that my prototype and the tridentimageextractor 
produce look almost the same as the .bmp thumbnail.  This also fixed the 
vertical distortion problem for the preview item in the Details view.

Short of forcing the original images we use for thumbnails to always be 
96x96, I can't find a really straightforward example of doing shell extension 
thumbnail extractors from an actual bitmap (pre-Vista) anywhere .  (The only 
complete example I've found is on CodeProject for the MFC Scribble example, 
but it's bound up with reusing the wrapped GDI objects from the MFC doc/view 
implementation of the original app.  The only examples I've found on MSDN are 
a couple of Dino Esposito's shell extension articles from (way) back issues 
of MSDN Magazine, and in the very simple thumbnail examples he gave to 
illustrate the facility, he just grabbed an existing resource icon.)

I've pieced the following code together from various sources.  Oddly, and 
maybe this is a clue, I get the same thumbnail image result with the 
non-96x96 original bitmaps if I just Detach() the bitmap from the CImage and 
don't even attempt the scaling.  (Uses Visual Studio 2008 ATL.  The m_bmSize 
width/height member is stored from the preceding IExtractImage GetLocation 
call's 'const SIZE *prgSize' parameter which is supposed to suggest the size. 
m_szFile is the pathname that comes from the IPersistFile::Load call.)


STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{ 
	CImage ciTheImage;
	ciTheImage.Load(m_szFile);
	HDC hmemDC = CreateCompatibleDC(NULL);
	SetStretchBltMode(hmemDC, HALFTONE);
	SetBrushOrgEx (hmemDC, 0, 0, NULL);

    HBITMAP hmemBM = CreateCompatibleBitmap (hmemDC, m_bmSize.cx, 
m_bmSize.cy );
    SelectObject (hmemDC, hmemBM);

	ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy, HALFTONE);

	*phBmpThumbnail = ciTheImage.Detach();
	DeleteDC(hmemDC);
	DeleteObject(hmemBM);

	return NOERROR; 
}
date: Tue, 1 Apr 2008 09:03:02 -0700   author:   linearred

Re: Windows XP thumbnail shell extension   
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
> HALFTONE); 

StretchBlt uses a very low quality scaling algorithm. To get decent results you need to use something like GDI (which is what the built-in thumbnailer uses).

-- 
Jim Barry, Microsoft MVP
date: Tue, 1 Apr 2008 18:26:50 +0100   author:   Jim Barry

Re: Windows XP thumbnail shell extension   
Jim Barry wrote:
> linearred wrote:
>> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
>> HALFTONE); 
> 
> StretchBlt uses a very low quality scaling algorithm. To get decent results you need to use something like GDI+ (which is what the built-in thumbnailer uses).

By default...
You can use SetStretchBltMode which significantly improves quality, but 
also slows it down, btu this may not be a problem for you.
When I was doing it several hundred times a second, it was an issue :)

-- 
Dean Earley (dean.earley@icode.co.uk)
i-Catcher Development Team

iCode Systems
date: Wed, 02 Apr 2008 09:34:54 +0100   author:   Dean Earley

Re: Windows XP thumbnail shell extension   
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy, HALFTONE); 

Hmmm, that last parameter is supposed to be a ROP code, i.e. SRCCOPY. I'm surprised you're seeing anything on the screen at all.

-- 
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 16:09:57 +0100   author:   Jim Barry

Re: Windows XP thumbnail shell extension   
Dean Earley wrote:
> By default...
> You can use SetStretchBltMode which significantly improves quality,

Well, even with STRETCH_HALFTONE the results are not too great. GDI is better but even when CompositingQualityGammaCorrected is set, the GDI scaler doesn't take gamma into account. It seems that the only way to get the correct result is to do everything yourself from scratch.

-- 
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 16:10:56 +0100   author:   Jim Barry

Re: Windows XP thumbnail shell extension   
Hi Jim,

I was using SRCCOPY originally - not sure where I picked up the idea that I 
could try HALFTONE.  SRCCOPY doesn't have any effect on the image, and I 
just changed it back to verify that.  I think this goes back to the 
observation that if I completely skip all the scaling steps and just load 
the image from the file and then just detach() the bitmap and give it to the 
shell, I get the same results.  It's as if the StretchBlt here has no effect 
at all, or at least not on the bitmap it returns the handle to.

Thanks.
"Jim Barry"  wrote in message 
news:%23E0seONlIHA.5396@TK2MSFTNGP04.phx.gbl...
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy, HALFTONE);

Hmmm, that last parameter is supposed to be a ROP code, i.e. SRCCOPY. I'm 
surprised you're seeing anything on the screen at all.

-- 
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 12:53:46 -0500   author:   linearred

Re: Windows XP thumbnail shell extension   
Thanks for the suggestion, Dean.

"Dean Earley"  wrote in message 
news:eJYZtxJlIHA.5080@TK2MSFTNGP02.phx.gbl...
> Jim Barry wrote:
>> linearred wrote:
>>> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
>>> HALFTONE);
>>
>> StretchBlt uses a very low quality scaling algorithm. To get decent 
>> results you need to use something like GDI+ (which is what the built-in 
>> thumbnailer uses).
>
> By default...
> You can use SetStretchBltMode which significantly improves quality, but 
> also slows it down, btu this may not be a problem for you.
> When I was doing it several hundred times a second, it was an issue :)
>
> -- 
> Dean Earley (dean.earley@icode.co.uk)
> i-Catcher Development Team
>
> iCode Systems
date: Wed, 2 Apr 2008 12:54:17 -0500   author:   linearred

Re: Windows XP thumbnail shell extension   
Hi Jim,

Thanks for the suggestion.  I found two different approaches to doing this 
with GDI+  but I can't get either to work.

Using GetThumbnailImage:

 GdiplusStartupInput gdiplusStartupInput;
 ULONG_PTR gdiplusToken;
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 Image imgTheImage(m_szFile, FALSE);
 Bitmap *pbmScaledBitmap =
  (Bitmap*)imgTheImage.GetThumbnailImage(m_bmSize.cx, m_bmSize.cy, NULL, 
NULL);

 Color cBackgroundColor(255, 255, 255);
 pbmScaledBitmap->GetHBITMAP(cBackgroundColor, phBmpThumbnail);

 Gdiplus::GdiplusShutdown(gdiplusToken);
------------
Using DrawImage:
 Image imgSourceImage(m_szFile, FALSE);

 Bitmap bmScaledBitmap(m_bmSize.cx, m_bmSize.cy, 
imgSourceImage.GetPixelFormat());
 Graphics gGraphicSurface(&bmScaledBitmap);

 gGraphicSurface.SetSmoothingMode(SmoothingModeHighQuality);
 gGraphicSurface.SetInterpolationMode(InterpolationModeHighQualityBicubic);

 Image *pimgSourceImage = &imgSourceImage;
 gGraphicSurface.DrawImage(pimgSourceImage, 0, 0, m_bmSize.cx, m_bmSize.cy);

 Color cBackgroundColor(255, 255, 255);
 HBITMAP phbmScaledBitmap;
 bmScaledBitmap.GetHBITMAP(cBackgroundColor, &phbmScaledBitmap);

 phBmpThumbnail = &phbmScaledBitmap;

 Gdiplus::GdiplusShutdown(gdiplusToken);

The actual GDI+ calls all appear to return "OK", but both approaches get 
access violations that appear to be in the Image destructor after the 
function ends.  I'm not real familliar with what these things are supposed 
to look like underneath the pointers, but it also looks like maybe the 
bitmap handle isn't really getting loaded.

By the way -- you wouldn't happen to know if the shell extension actually 
needs to call  the GDIplus Startup and Shutdown methods, would you?

Thanks for the help.

"Jim Barry"  wrote in message 
news:eQoAT2BlIHA.5088@TK2MSFTNGP02.phx.gbl...
linearred wrote:
> ciTheImage.StretchBlt(hmemDC, 0, 0, m_bmSize.cx, m_bmSize.cy,
> HALFTONE);

StretchBlt uses a very low quality scaling algorithm. To get decent results 
you need to use something like GDI+ (which is what the built-in thumbnailer 
uses).

-- 
Jim Barry, Microsoft MVP
date: Wed, 2 Apr 2008 13:01:43 -0500   author:   linearred

Re: Windows XP thumbnail shell extension   
linearred wrote:
> The actual GDI calls all appear to return "OK", but both approaches
> get access violations that appear to be in the Image destructor after
> the function ends.  

You mustn't shut down GDI until you have completely finished with it, and this includes the destructors of any GDI objects you have created. For a "one off" use of GDI, you can make sure the destructors run first by introducing a new scope:

GdiplusStartup(...);
{
  // Do stuff
}
GdiplusShutdown(...);

In a shell extension, you could call GdiplusStartup when your extension object is created and GdiplusShutdown when it is destroyed.

-- 
Jim Barry, Microsoft MVP
date: Thu, 3 Apr 2008 16:26:23 +0100   author:   Jim Barry

Re: Windows XP thumbnail shell extension   
Hi Jim --

Thanks for the tip!  Just wrapping the GDI+ scaling code in the block like 
you suggested fixed the destructor access violations.

I have two implementations that don't crash, but they still produce the same 
coarse image when the image has to be scaled (relative to what the .bmp 
thumbnails look like for the same data), and each has its own scaling 
glitches when the folder View is set to "Details" and they have to produce 
the 150x100 preview image that appears in the lower left of the folder 
frame.  (On the two XP boxes I use, GetLocation also asks for 32 bit color 
in the Details preview image, as opposed to the 24 bit 96x96 image requested 
in the "Thumbnails" View mode.)

Now that it doesn't crash : ) , I'll play around with the smoothing and 
other settings on the Graphics object to see if I can improve the rendering.

(Note - the additional block doesn't seem to be necessary if the Graphics 
object isn't created.)

STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{
 GdiplusStartupInput gdiplusStartupInput;
 ULONG_PTR gdiplusToken;
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 Bitmap *pbmOriginal = Bitmap::FromFile(m_szFile);

 Color bgColor(255, 255, 255);
 pbmOriginal->GetHBITMAP(bgColor, phBmpThumbnail);

 Gdiplus::GdiplusShutdown(gdiplusToken);

 return NOERROR;
}



STDMETHODIMP CmyThumbGetter::Extract(HBITMAP* phBmpThumbnail)
{
 GdiplusStartupInput gdiplusStartupInput;
 ULONG_PTR gdiplusToken;
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

 {
  Bitmap bmOriginal(m_szFile, FALSE);
  Bitmap bmScaledBitmap(m_bmSize.cx, m_bmSize.cy, 
bmOriginal.GetPixelFormat());

  Graphics gGraphics(&bmScaledBitmap);
  gGraphics.DrawImage(&bmOriginal, 0, 0, m_bmSize.cx, m_bmSize.cy);

  Color bgColor(255, 255, 255);
  bmScaledBitmap.GetHBITMAP(bgColor, phBmpThumbnail);
 }

 Gdiplus::GdiplusShutdown(gdiplusToken);

 return NOERROR;
}



"Jim Barry"  wrote in message 
news:uTh8U8ZlIHA.2368@TK2MSFTNGP03.phx.gbl...
linearred wrote:
> The actual GDI+ calls all appear to return "OK", but both approaches
> get access violations that appear to be in the Image destructor after
> the function ends.

You mustn't shut down GDI+ until you have completely finished with it, and 
this includes the destructors of any GDI+ objects you have created. For a 
"one off" use of GDI+, you can make sure the destructors run first by 
introducing a new scope:

GdiplusStartup(...);
{
  // Do stuff
}
GdiplusShutdown(...);

In a shell extension, you could call GdiplusStartup when your extension 
object is created and GdiplusShutdown when it is destroyed.

-- 
Jim Barry, Microsoft MVP
date: Thu, 3 Apr 2008 12:17:50 -0500   author:   BW noway

Re: Windows XP thumbnail shell extension   
PS -- It also helps to remember that  the GetLocation cache flag needs to be 
unset and the hidden thumbs.db removed from the test image folder on each 
run when debugging so you can verify what your changes are actually doing!
date: Thu, 3 Apr 2008 12:42:48 -0500   author:   BW noway

Re: Windows XP thumbnail shell extension   
PS -- It also helps to remember that  the GetLocation cache flag needs to be
unset and the hidden thumbs.db removed from the test image folder on each
run when debugging so you can verify what your changes are actually doing!
date: Thu, 3 Apr 2008 12:43:16 -0500   author:   BW noway

Re: Windows XP thumbnail shell extension   
It looks like at least part of the vertical "stretching" scaling problem I'm 
seeing in some of  the "Details" preview images is because one of the 
components is deciding to crop the original image to its topmost row of 
foreground pixels, and then (possibly something else) appears to try to 
scale the cropped image over the original dimensions.  I have another image 
that gets stretched a bit horizontally, so I'll need to check if it's 
getting some background cropped on the edge.
date: Thu, 3 Apr 2008 13:19:17 -0500   author:   linearred noway

Re: Windows XP thumbnail shell extension   
Hey Jim, thanks for the help.  I solved my GDI+ scaling problem that was 
causing the thumbnail to look a bit "stretched".  I had to use 
SmoothingModeHighQuality and InterpolationModeHighQualityBicubic to recover 
the resolution, but, except that the .bmp extractor appears to pad the top 
rows of its image, I appear to be producing a thumbnail of the same quality.

Thanks again.
date: Sun, 6 Apr 2008 18:02:41 -0500   author:   linearred noway

Re: Windows XP thumbnail shell extension   
linearred wrote:
> Hey Jim, thanks for the help.  I solved my GDI scaling problem that
> was causing the thumbnail to look a bit "stretched".  I had to use
> SmoothingModeHighQuality and InterpolationModeHighQualityBicubic to
> recover the resolution, but, except that the .bmp extractor appears
> to pad the top rows of its image, I appear to be producing a
> thumbnail of the same quality. 

Not sure if I understand you correctly, but you may want to set the pixel offset mode to PixelOffsetModeHalf. By the way, the smoothing mode only applies to lines and curves, and shouldn't have any effect on bitmap scaling.

-- 
Jim Barry, Microsoft MVP
date: Mon, 7 Apr 2008 12:14:31 +0100   author:   Jim Barry

Re: Windows XP thumbnail shell extension   
"Jim Barry"  wrote in message
news:%23mipQCKmIHA.5684@TK2MSFTNGP03.phx.gbl...

Not sure if I understand you correctly, but you may want to set the pixel
offset mode to PixelOffsetModeHalf. By the way, the smoothing mode only
applies to lines and curves, and shouldn't have any effect on bitmap
scaling.

-- 
Jim Barry, Microsoft MVP

Hey Jim,

Thanks for the smoothing tip.  What I thought was "padding" actually looks
like the built-in .bmp extractor centering its image in the thumbnail.  I
just started drawing the image at 0, 0.  My test image just happens to look
more like the original Paint canvas because it had data along the top of the
canvas, but didn't have data along the bottom of the canvas.  When I added
something at the bottom of the Paint canvas, it was obvious that there was
actually empty space below the image in the thumbnail canvas.

Thanks again.
date: Mon, 7 Apr 2008 10:45:30 -0500   author:   linearred noway

Google
 
Web ureader.com


    COPYRIGHT 2007, YARDI TECHNOLOGY LIMITED, ALL RIGHT RESERVE  |   contact us