GDI: Do not redraw the window after each output

I have a matrix 512*512, containing a color value. I want to draw on the screen an image, where each pixel will be at the color, defined by my matrix. I mustn't pass by image, but only using directly GDI output to the screen. If I output all pixels one by one, the entire time of outputing 512^2 pixels is about 5 seconds. It seems that GDI redraws the window each time it outputs a pixel. I'm right, am I? How is it possible to redraw only once, at the end, when all pixels are set?

How Paint does? It also inputs each pixel, but it doesn't take much time?

Thanks,
MainMa
MainMaAsked:
Who is Participating?
 
joghurtCommented:
1. No. If it were redrawn, you would have to begin the painting again, triggering another repaint, etc.
2. There are various functions in the Windows API dealing with bitmap operations. For your purpose see BitBlt, StretchBlt/StretchDIBits and SetDIBits.
3. It's quite easy. Supposing you have an array of RGB values. The pixels are organized by line, for example
0 1 2 3
4 5 6 7

LONG picWidth = ...;      // Image width in pixels, MUST be a multiple of 4.
LONG picHeight = ...;      // Image height in pixels.
void* picPtr = ...;           // Image data

BITMAPINFO bmi;
ZeroMemory (&bmi, sizeof (bmi));
bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
bmi.bmiHeader.biBitCount = 24;              // 24-bit image, you can specify 32 if you have 32-bit (A)RGB values in your array.
bmi.bmiHeader.biClrImportant = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biCompression = BI_RGB;   // On Win98/Me and Win2k/XP you can specify BI_JPEG and BI_PNG if you pass a jpeg or png image
bmi.bmiHeader.biWidth = picWidth;
bmi.bmiHeader.biHeight = picHeight;        // If it's positive: bottom-up bitmap, if it's negative: top-down bitmap
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biXPelsPerMeter = GetDeviceCaps (hDC, HORZRES) / GetDeviceCaps (hDC, HORZSIZE);
bmi.bmiHeader.biYPelsPerMeter = GetDeviceCaps (hDC, VERTRES) / GetDeviceCaps (hDC, VERTSIZE);
bmi.bmiHeader.biSizeImage = 0;             // Must be set to zero for BI_RGB images.

StretchDIBits (hDC, 0, picWidth, picWidth, -picWidth, 0, 0, picWidth, picPtr, &bmi, DIB_RGB_COLORS, SRCCOPY);
// Check documentation for parameters of StretchDIBits
0
 
joghurtCommented:
No, it's SetPixel that is slow, not the redraw.

You should create a bitmap in the memory (don't worry, in fact you have only to create a bitmap header) and use bitmap drawing functions.

What kind of colour array do you have? RGB values on three bytes for each pixel, ARGB values on four bytes or do you have some indexed image?
0
 
MainMaAuthor Commented:
1. Were I right when I said that in fact, the window is redrawed each time I draw a pixel?
2. How does Windows do to output to the screen a bitmap created in memory? There must be some function in some Windows DLL which does it...
3. I had an idea of using bitmap images like you said, but I hadn't got too much information. Can you give an idea of something, which will output an image, built from array of RGB values?

Thanks,
MainMa
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
MainMaAuthor Commented:
Help!
> void* picPtr = ...; // Image data
What type of variable must-it be? I tried to set a matrix "COLORREF Matrix[size][size];" but I can's see something correct on the screen (horisontal red/green/blue/black lines). If, instead of COLORREF I use int, the result is the same!
0
 
joghurtCommented:
A COLORREF is 4-bytes large, so in this case you should change bmi.bmiHeader.biBitCount to 32. The same applies to "int".
Do you have any special reason for using COLORREFs for each pixel instead of 24-bit values? This latter one can be done by using a simple character (or BYTE) array in which the R, G and B bytes come after each other: R1, G1, B1, R2, G2, B2...
BYTE Matrix[size][size * 3];

Btw, how do you initialize this array?
0
 
MainMaAuthor Commented:
This is my new code:

----------------------------------------------------------------------------------------------------
BYTE Matrix[8][8*3];
// Fill some cells
void initialise()
{
      Matrix[0][0] = 255; Matrix[0][1] = 0; Matrix[0][2] = 0;
      Matrix[0][3] = 0; Matrix[0][4] = 255; Matrix[0][5] = 0;
      Matrix[0][6] = 0; Matrix[0][7] = 0; Matrix[0][8] = 255;
      Matrix[0][9] = 255; Matrix[0][10] = 255; Matrix[0][11] = 0;
}
[...]
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
      LONG picWidth = 8; // Image width in pixels, MUST be a multiple of 4.
      LONG picHeight = 8; // Image height in pixels.
      void* picPtr = &Matrix; // Image data
[...]
case WM_PAINT:
      StretchDIBits(hdc,
            10, 10, picWidth*20, picHeight*20,
            0, 0, picWidth, picHeight,
            picPtr, &bmi, DIB_RGB_COLORS, SRCCOPY);
[...]
----------------------------------------------------------------------------------------------------

OK, it works, but first, "Matrix[0][0] = 255; Matrix[0][1] = 0; Matrix[0][2] = 0;" gives a blue pixel instead of red one, green stays green, and blue becomes red. I can, of course, invert each time first and third values, but maybe this invertion is an error...
It seems to me that having BYTE Matrix[size][size*3]; is compicated to store an image. For example, when I would store 1024*1024 image, it will take too much time to the program to convert Matrix1[a][b][3] to Matrix2[a][b*3].
0
 
joghurtCommented:
Sorry, it was my fault, not yours. Parameter order for the RGB macro is R, G, B but in the memory the byte order is reversed so it's B, G, R.

In my view Matrix1[a][b][3] and Matrix2[a][b*3] are equivalent in the memory. So you can use the first declaration if you prefer that one.
0
 
MainMaAuthor Commented:
Thank you, all works.
0
 
MainMaAuthor Commented:
Just another question: how can I load an image (a file) to Matrix1[a][b][3] (we suppose that the size of image is a*b)?
0
 
joghurtCommented:
If you have a bitmap file, you don't have to do the above trick. A simple LoadImage will supply you with a HBITMAP that can be used for drawing. But that's another question.
0
 
MainMaAuthor Commented:
Yes, I know. But if i want precisely to load a file into a matrix, how can I do it?
0
 
joghurtCommented:
Ask a new question. It has nothing to do with the current topic.
0
 
MainMaAuthor Commented:
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.