|
|
Hi All,
I have a resolution problem when drawing a bitmap to the screen using GDI+ methods. The bitmaps I am dealing with are typically in the order of 2304 x 1728 pixels and I normally shrink these to around 276 x 207 pixels.
Users of my application have a choice of viewing the bitmap normally or rotated +/- 90 degrees. When applying rotation the image is rendered pin sharp. However, when no rotation is applied, the image is only of average quality - irrespective of how high I set the interpolation and smoothing modes. It is interesting that explicitly setting the interpolation/smoothing modes when rotating also renders an average quality image.
Is there an explanation for what I am seeing here? More to the point, is there any way I can get the same razor sharp images when not rotating as when I am rotating?
Thanks, Graham
Code sample and details as follows..
using namespace Gdiplus;
int top_left_x, top_left_y, new_width, new_height;
// Create a Bitmap object based on a given image file
BITMAP *pGDIBitmap = Bitmap::FromFile(filename, TRUE);
// Calculate offsets and new dimensions
GetOffsets(pGDIBitmap, top_left_x, top_left_y, new_width, new_height);
// Create a GDI Plus graphics object
Graphics graphics(pDC->GetSafeHdc( ) );
// Translate prior to rotation (if any)
graphics.TranslateTransform(top_left_x, top_left_y);
// Check for rotation request
if (bRotateImage)
{
// Invoke rotate transform
graphics.RotateTransform(90.0f);
}
else
{
// Set some properties, to ensure to have a better quality of image
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
graphics.SetSmoothingMode(SmoothingModeAntiAlias);
}
// Draw the image
draw_status = graphics.DrawImage(pGdiBitmap, 0.0f , 0.0f, new_width, new_height);
etc, etc. . .
// Development environment - Microsoft Visual C++ (.NET v8)
// Operating system - Windows 2000
// Monitor - Iiyama A102GT
// Graphics monitor - Intel 82815
// Screen area - 1280 x 1024
// Refresh rate - 75Hz
Graham
|
|
|
|
|
It doesn't make sense that the rotated image would be better quality than not rotated.
I only see three things I'd do differently from your code..
1) I prefer to apply RotateTransfor BEFORE TranslateTransform (seems to give better results to
me).
2) SetSmoothingMode I thought was just for lines/curves but if it applies smoothing to images
I certainly wouldn't want that effect, unless I was specifically smoothening an image.
3) The interpolation mode should be set before any rotation or scaling.
What happens if you do this:
using namespace Gdiplus;
int top_left_x, top_left_y, new_width, new_height;
// Create a Bitmap object based on a given image file
BITMAP *pGDIBitmap = Bitmap::FromFile(filename, TRUE);
// Calculate offsets and new dimensions
GetOffsets(pGDIBitmap, top_left_x, top_left_y, new_width, new_height);
// Create a GDI Plus graphics object
Graphics graphics(pDC->GetSafeHdc( ) );
// Set some properties, to ensure to have a better quality of image
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
//graphics.SetSmoothingMode(SmoothingModeAntiAlias);
// Check for rotation request
if (bRotateImage)
{
// Invoke rotate transform
graphics.RotateTransform(90.0f);
}
// Translate
graphics.TranslateTransform(top_left_x, top_left_y);
// Draw the image
draw_status = graphics.DrawImage(pGdiBitmap, 0.0f , 0.0f, new_width, new_height);
etc, etc. . .
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
Hi Mark,
Thanks for your reply. I take your point regarding the smoothing mode and I've now removed this from my code - but to no effect I'm affraid.
I perfrom the translation prior to rotation simply to facilitate calculation of the x/y offsets. In any case, the poor image quality only occurs whenever I do NOT rotate so this is not the source of the problem. Also, when I rotate, the image is only rendered sharp if I do NOT specify the interpolation mode. I get the impression that 'RotateTransform' is doing something behind the scenes that neither of us are aware of.
Before I delve further into this, I want to eliminate any possibility the the hardware I'm working with is affecting what I am seeing. Later today, I will transfer my exe to a new machine with a different monitor and see if I can repeat the problem.
Cheers, Graham
|
|
|
|
|
HuddartG wrote: In any case, the poor image quality only occurs whenever I do NOT rotate so this is not the source of the problem.
Right. I'm with you. The image should be sharp just drawing it with no transformation. This
part seems strange (as you know).
I typically don't use interpolation when reducing image size because the images I work with don't
have text so simply removing pixels is sufficient. When expading an image, interpolation is nice
to prevent pixelization blockiness.
HuddartG wrote: I perfrom the translation prior to rotation simply to facilitate calculation of the x/y offsets.
Right, but the order you apply transformations is important in GDI+. In my experience I get
better results applying translation last. That's why I suggested trying that.
Here's more info: Matrix Representation of Transformations[^]
I'd try getting it all working without interpolation or smoothing - just rotation and translation.
It's easy enough to add the interpolation
Still, the image should be crisp with no transformations applied so that's still a mystery.
Please let me know how your testing comes out.
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
Hi Mark,
Thanks for your reply. I tried my application on a different machine/monitor and I had exactly the same problem.
I then asked myself what GDI+ could be doing when rotating as opposed to not rotating. After hitting on several websites (including "http://www.leunen.com/cbuilder/rotbmp.html") I concluded that there must be some copying taking place. I then experimented by taking a clone of my original bitmap and my findings were interesting to say the least. Let me first show you my latest modified code..
// Create a GDI Plus graphics object
Graphics graphics(pDC->GetSafeHdc( ) );
etc, etc..
// Get size and offset depending on orientation and aspect of image (my function)
GetSizeAndOffset(RectImage, Orientation, orig_width, orig_height, new_width, new_height, top_left_x, top_left_y);
// Translate the origin
graphics.TranslateTransform(top_left_x, top_left_y);
// Check for rotation request
if (bRotate)
{
// Apply rotation
graphics.RotateTransform(Orientation); // No problem if do this
}
else
{
UINT u_width = pGdiBitmap->GetWidth( ); // Typically 2303
UINT u_height = pGdiBitmap->GetHeight( ); // Typically 1727
// If I decrement by 1 (or more) then the image quality is superb. With zero decrement
// I get the same poor resolution as before. If I increment then I get no image at all.
u_width -= 1;
u_height -= 1;
// Store pointer to original bitmap
Bitmap *pOriginalBitmap = pGdiBitmap;
// Get a slightly reduced clone of the original
pGdiBitmap = pOriginalBitmap->Clone(0, 0, u_width, u_height, PixelFormatDontCare);
// Calling this will actually degrade image quality
// graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
// Release the original bitmap
delete pOriginalBitmap;
}
// Draw the image
draw_status = graphics.DrawImage(pGdiBitmap, 0.0f , 0.0f, new_width, new_height);
etc, etc..
If I clone only a portion of my original bitmap then I get sharp images (even without promoting the interpolation mode). If I maintain the size of the bitmap then poor image quality returns. Interestingly, I get degradation of image quality if I promote the interpolation mode.
The upshot of all this is that I have partially solved my problem. However, I do suffer a slight loss data (though not a big issue) and I also take a hit on performance due to cloning.
I am puzzled, however, as to why I am experiencing this phenomenon. I do not see how simply reorganising the bits in the bitmap can be enhancing image quality. Looking once again at "www.leunen.com/cbuilder/rotbmp.html" my suspicions now centre on the DIB section. Could it be that GDI+ is, under certain conditions, modifying DIB section attributes when rotating/cloning? If so then I can modify these attributes for myself without the need to clone. I would appreciate your comments on this.
Cheers, Graham
Graham
|
|
|
|
|
How to hide Dos window from .msi file ?
|
|
|
|
|
Is this MSI you have created or you got it from somewhere?
|
|
|
|
|
Hello all,
I linked a lib file say sss.lib with myapp.exe.
when I tried to access a string from a string table of sss.lib, I got '1814' error msg.
The code is
{
#if defined _ATL
HINSTANCE hInst = _Module.GetModuleInstance();
#else
HINSTANCE hInst = GetModuleHandle(NULL);
#endif
TCHAR buff[1025];
GetModuleFileName(hInst,buff,sizeof(buff)/sizeof(TCHAR));
unsigned nID = 101;
DWORD dw;
LoadString(hInst,nID,buff,sizeof(buff)/sizeof(TCHAR));
if(!LoadString(hInst,nID,buff,sizeof(buff)/sizeof(TCHAR)))
dw = GetLastError();
AfxMessageBox(buff);
}
I don't know how to pull off this.Can you halp me?
Thanks,
GAN
|
|
|
|
|
i have a dll project,and i want to invoke word.exe debugging my dll.i find that i failed.
ytfrdfiw
|
|
|
|
|
Project->Properties->Debbuging->Command in your dll project set to WINWORD.EXE
Best regards,
Baron
|
|
|
|
|
thank you for your answer,but i can't find project->properties in my vc6.0.
ytfrdfiw
|
|
|
|
|
then search again
(of course, no need to say that you must have opened your workspace firstly )
|
|
|
|
|
then search again
i don't understand what you want to say.
but i have opened my workspace.
ytfrdfiw
|
|
|
|
|
Open your workspace (dll project) and press F5 button. After that you'll see small dialog box where you can browsing folders and choosing start-up programm. Try doing something with it
Best regards,
Baron
|
|
|
|
|
after 3 years ,i can do it now,thanks for everyone replying my question
ytfrdfiw
|
|
|
|
|
Hi
If I have the function
<br />
int * foo()<br />
{<br />
int x = 6;<br />
int * ptr = &x;<br />
return ptr;<br />
<br />
}<br />
<br />
<br />
I was wondering how this works because the local variable x is destroyed upon leaving the function so doesn'nt the pointer ptr be invalid? Also, is the copy constructor called in returning ptr? And is ptr destroyed upon leaving the function since that goes out of scope too?
Thanks for any answers.
|
|
|
|
|
See Here[^] it is a very good article about pointers ...
Regards,
The only programmers that are better than C programmers are those who code in 1's and 0's.....
Programm3r
My Blog: ^_^
|
|
|
|
|
BTW the function is full of mistakes. And your hypothes are correct. However, for a while the values are available (they aren't immediatly overwritten). Of course you cannot do any assumption on their correctness in calling code.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
Hi ya
Why is my function full of mistakes? I ran the code and it works ok.
So in the function, x is available till it is over written which is why it works?
Is a copy constructor used in returning the ptr from the function ?
Thanks.
|
|
|
|
|
You function works perfectly, what you return is a the location that the function stored x. As to whether this is of any use depends on what is currently stored in that location - if you call another function the location will almost certainly be reused.
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Hi ya,
But I thought that x goes out of scope which means it is released. So since ptr is pointing to x then that is not valid. However, I know this works (having tried it) so the reasoning seems to be although that x goes out of scope, the memory has not been yet over written so it works.
Is that right?
And is a copy constructor called in returning the pointer?
Thanks.
|
|
|
|
|
actually, x went out of scope, so the variable x is destroyed, but even if is x doesn't exist anymore, what you get with the pointer is the address at which x was stored...
so, yes, the memory occupied by x is released (so that any other memory request could use this space), but not overwritten, that means that the value persists until some write a new variable's value on it.
you musn't do the asumption that immediately when exiting your function, the caller can get the value pointed by x though
|
|
|
|
|
Well, there is only a big mistake: you're are returning a pointer to a temporary value, this you must never do, because calling code cannot consider reliable the pointer.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
Hi CPallini,
Yes I agree with that and I was wondering why it still works.
How is the pointer returned? Is it copied with a copy constructor?
Thanks.
|
|
|
|
|