Good idea here? I think so...
When dealing with device contexts in the past, I noticed that when shrinking images with StretchDIBits or StretchBlt with a bitmap selected into a memory DC, the images would not be smooth or correct.
So I wrote my own bitmap class. Here is the definition of it from my header file. Of course it relies on other classes, but this is just the interface.
Code:
class LORE_CORE_CLASS Bitmap : public GdiObject,public IImage
{
public:
Bitmap() throw();
Bitmap(HBITMAP hBitmap,bool bSystem) throw();
Bitmap(HBITMAP hBitmap,unsigned long * pPixelData) throw();
virtual ~Bitmap() throw();
// IImage
virtual Size GetSize() const throw();
virtual bool Resize(long nWidth,long nHeight) throw();
virtual bool Resize(Size nSize) throw();
virtual ColorValue * GetPixels() throw();
virtual const ColorValue * GetPixels() const throw();
virtual bool Scale(long nNewWidth,long nNewHeight,IImage * pDestImage) const throw();
virtual bool Scale(Size nNewSize,IImage * pDestImage) const throw();
virtual IImage * Scale(long nNewWidth,long nNewHeight) const throw();
virtual IImage * Scale(Size nNewSize) const throw();
virtual IImage * Scale(double lfRatio) const throw();
virtual IImage * Scale(double lfWidthRatio,double lfHeightRatio) const throw();
virtual bool CopyBlt(long srcX,long srcY,long nWidth,long nHeight,IImage * pDestImage,long destX,long destY) const throw();
virtual bool CopyBlt(const Point & src,const Size & nSize,IImage * pDestImage,const Point & dest) const throw();
virtual bool CopyBlt(const Rect & src,IImage * pDestImage,const Point & dest) const throw();
virtual IImage * CopyBlt(long srcX,long srcY,long nWidth,long nHeight) const throw();
virtual IImage * CopyBlt(const Point & src,const Size & nSize) const throw();
virtual IImage * CopyBlt(const Rect & src) const throw();
virtual bool StretchRect(const Rect & src,IImage * pDestImage,const Rect & dest) const throw();
virtual IImage * StretchRect(const Rect & src,const Size & nNewSize) const throw();
// Member Functions
void BltToHDC(HDC hDC,long x,long y) throw();
// Static Member Functions
static Bitmap * __stdcall CreateDIB(long nWidth,long nHeight) throw();
static Bitmap * __stdcall FromHDC(HDC hDC,long x,long y,long nWidth,long nHeight) throw();
static Bitmap * __stdcall LoadFromFile(const AnsiString & strFileName) throw();
static Bitmap * __stdcall LoadFromFile(const UnicodeString & strFileName) throw();
protected:
// Member Variables
unsigned long * PixelData;
Size Dimensions;
// Member Functions
void CopyLine(const Point & src,long nwidth,IImage * pDest,const Point & dest) const throw();
void StretchLine(const Point & src,long nWidth,IImage * pDest,const Point & dest,long nDestWidth) const throw();
void ShrinkLine(const Point & src,long nWidth,IImage * pDest,const Point & dest,long nDestWidth) const throw();
inline static ColorValue GetPixel(const ColorValue * pPixels,const Size & nDim,const Point & src) throw()
{
ColorValue clrValue = 0;
const long nHeight = nDim.Height;
const long nWidth = nDim.Width;
if (src.PosY >= 0 && src.PosY < nHeight && src.PosX >= 0 && src.PosX < nWidth)
{
const long nPosition = ((nHeight - src.PosY - 1) * nWidth) + src.PosX;
clrValue = pPixels[nPosition];
}
return clrValue;
}
inline static void SetPixel(ColorValue * pPixels,const Size & nDim,const Point & dest,ColorValue value) throw()
{
const long nHeight = nDim.Height;
const long nWidth = nDim.Width;
if (dest.PosY >= 0 && dest.PosY < nHeight && dest.PosX >= 0 && dest.PosX < nWidth)
{
const long nPosition = ((nHeight - dest.PosY - 1) * nWidth) + dest.PosX;
pPixels[nPosition] = value;
}
}
};
Now, my question is, when I get to writing the device context classes (PaintDC, ClientDC, WindowDC, MemoryDC, PrintDC) obviously only the memory DC will be able to have a bitmap selected into it...
So I am thinking... When I implement StretchBlt for the DCs, I should just call Bitmap::FromHDC to get a bitmap object that I want to stretch, stretch that into another, then use member function BltToHDC.
That will make alot of temporary memory overhead.
However, this way assures that the output will not look distorted/torn like StretchBlt and StretchDIBits have done on several occasions to me.
What do you think?
Re: Good idea here? I think so...
I'm not knocking what you've created, but if you did all of that because StretchBlt is causing distortion, you must be doing something wrong. I've never had StretchBlt perform unsatisfactorily, except maybe for speed. Then I found a workaround for that.
Did you SetStretchBltMode?
Re: Good idea here? I think so...
Quote:
Originally Posted by DHillard
I'm not knocking what you've created, but if you did all of that because StretchBlt is causing distortion, you must be doing something wrong. I've never had StretchBlt perform unsatisfactorily, except maybe for speed. Then I found a workaround for that.
Did you SetStretchBltMode?
I didn't do all that JUST BECAUSE of StretchBlt not working correctly. Actually, the implementation of that bitmap class was not THAT MUCH work. The algorithm for stretching/shrinking is not that difficult breaking it down the way I did. Second of all, it's part of my class hierarchy.
I have not tried SetStretchBltMode - however... It appears from the description of this function and it's parameters, that the stretching mode of StretchBlt for the device context has nothing to do with the problems I have experienced with StretchBlt and StretchDIBits.
2 Attachment(s)
Re: Good idea here? I think so...
(Yesterday I accidentally posted this in the wrong thread.)
Try the following attached file for what I mean about StretchBlt having bad results. Keep resizing the window. You will need to have a bitmap (*.bmp) in the same directory named "Test.bmp" without the quotes. This reproduces what I am talking about. Bare minimum.
Although, you do not see the rest of my library (let alone just Bitmap)...
Also is attached is the source of winmain which is very little different from the original file.
You may also find the results of compiling the winmain.cpp file at my Windows Spaces account. The link is the following: Fixed.exe - Compilation Results
View the source of both. Compile the temp.cpp yourself, run it... Download my compiled *.exe of the winmain.cpp file, and compare the results of both applications.
As far as the reference to SetStretchBltMode (and also the parameter passed to StretchBlt at the end, SRCOPY, etc...) I have that taken care of....
Code:
// Function Pointer Definitions
void (Bitmap::*StretchLine)(const Point &,long,Bitmap *,const Point &,long) const;
void (Bitmap::*ShrinkLine)(const Point &,long,Bitmap *,const Point &,long) const;
void (Bitmap::*CopyLine)(const Point &,long,Bitmap *,const Point &) const;
switch(enMode)
{
case Blt_Copy:
StretchLine = &Bitmap::StretchLine_C;
ShrinkLine = &Bitmap::ShrinkLine_C;
CopyLine = &Bitmap::CopyLine_C;
break;
case Blt_And:
StretchLine = &Bitmap::StretchLine_A;
ShrinkLine = &Bitmap::ShrinkLine_A;
CopyLine = &Bitmap::CopyLine_A;
break;
case Blt_Or:
StretchLine = &Bitmap::StretchLine_O;
ShrinkLine = &Bitmap::ShrinkLine_O;
CopyLine = &Bitmap::CopyLine_O;
break;
case Blt_Xor:
StretchLine = &Bitmap::StretchLine_X;
ShrinkLine = &Bitmap::ShrinkLine_X;
CopyLine = &Bitmap::CopyLine_X;
break;
default:
return false;
}
I was able to implement the other BLT operations with little modification. :cool:
Re: Good idea here? I think so...
I ran your fixed.exe program and I don't see the problem you're seeing. I wonder if it's because of a display driver difference. In other words, your "fixed" demo program looks just like my stretchblt applications. Or... did I misunderstand and the "fixed" demo is the "good" version?
I couldn't get your code to compile. Something about a link error to main or something. I can't remember the exact error message.
Could you do a screen capture of the distorted bitmap so I could compare those as images?
David
Re: Good idea here? I think so...
Quote:
Originally Posted by DHillard
I ran your fixed.exe program and I don't see the problem you're seeing. I wonder if it's because of a display driver difference. In other words, your "fixed" demo program looks just like my stretchblt applications. Or... did I misunderstand and the "fixed" demo is the "good" version?
I couldn't get your code to compile. Something about a link error to main or something. I can't remember the exact error message.
Could you do a screen capture of the distorted bitmap so I could compare those as images?
David
The temp.cpp file is the one you should be able to compile, you will not be able to compile winmain.cpp ---
Second of all, I did one better than a screen shot... I saved the contents of the bitmap results (getting from the HDC) of both just StretchBlt, and my Scale function + BitBlt.
123.bmp is just StretchBlt
124.bmp is my Scale function + BitBlt.
(I chose a random picture)
It seems I have a bug in my 24 bit bmp saving code... Doesn't matter, you can see a difference. Funny, a bug in my *.BMP saving code for 24bpp pixel maps actually shows HOW MUCH different the results are for StretchBlt and my Scale routine.
(EDIT... The bug happens to be that I forgot to increment an index when writing out the data, therefore... It wrote the first scanline every time. That's why they look the way they do) However... This proves that the first scanline from each one is VERY different from the other.
2 Attachment(s)
Re: Good idea here? I think so...
Okay... Fixed my bug in my program and got a chance to recompile to get the outputs again.
124.bmp is my algorithm's result.
123.bmp is StretchBlt's result.
Re: Good idea here? I think so...
Okay,
Thanks for those example photos. I've seen that before. That's solved with setting StretchBltMode to either HALFTONE, or COLORONCOLOR. I forget which. A simple one line fix.
David
1 Attachment(s)
Re: Good idea here? I think so...
No problem.
I had seen this in the past, and I thought I would post about it.
As far as relation to 'going to all that work'... Here is the main header for my library file so far. It's BY FAR not much work compare to all of it, or by itself it wasn't too much work. (The Bitmap class)
Re: Good idea here? I think so...
SetStretchBltMode did fix the problem when I set the mode to COLORONCOLOR.
Here is my modified WM_PAINT handler that fixed it. (NOTE: I have not gotten around to getting DeviceContext done, let alone PaintDC, etc... in my library, so bear with me in this code where I have DeleteDC.)
Code:
else if (message == WM_PAINT)
{
unsigned char ucValue = static_cast<unsigned char>(myRandom.Next());
ColorValue clrVALUE = Color::FromARGB(0,ucValue,ucValue,ucValue);
RECT rect;
GetClientRect(hWnd,&rect);
const long nNewWidth = rect.right - rect.left;
const long nNewHeight = rect.bottom - rect.top;
PAINTSTRUCT ps;
HDC hPaintDC = BeginPaint(hWnd,&ps);
HDC hSourceDC = ::CreateCompatibleDC(hPaintDC);
DeviceContext * pPaintDC = new DeviceContext(hPaintDC);
DeviceContext * pSourceDC = new DeviceContext(hSourceDC);
Bitmap * pBitmap = new Bitmap(TestBitmap,true);
Bitmap * pOld = pSourceDC->SelectBitmap(pBitmap);
pPaintDC->SetStretchBltMode(COLORONCOLOR);
pPaintDC->StretchBlt(Point(0,0),Size(nNewWidth,nNewHeight),pSourceDC,Point(0,0),Size(BitmapWidth,BitmapHeight),SRCCOPY);
pSourceDC->SelectBitmap(pOld);
delete pPaintDC;
delete pSourceDC;
delete pBitmap;
::DeleteDC(hSourceDC);
EndPaint(hWnd,&ps);
return 0;
}