Loading images for a 0x0 dummy window

Posted by Twisol on Sat 12 Dec 2009 05:22 PM — 8 posts, 19,627 views.

USA #0
(EDIT: MUSHclient v4.44)

First, see this snippet of script:

cg = CharacterGrid.new(3, 3)
cg:BackColor(0xFF0000)
cg:Anchor(12)
cg:Cell(1,1).backcolor = 0x00FF00
cg:Repaint()

w = "w"
WindowCreate(w, 0, 0, 0, 0, 0, 0, 0)
WindowImageFromWindow(w, "cg", cg.name)
WindowCreate(w, 0, 0, cg.width+4, cg.height+4, 12, 0, 0x0000FF)
WindowDrawImage(w, "cg", 2, 2, 0, 0, 1)
WindowShow(w)


The first window (cg) was created using my widget framework, though it could have been a regular window. The second is simply a window created to copy the first window into. If I were to call cg:Show(), the widget would look like [1] (large blue square w/ small green square). Running the above code, the 'w' window appears like [2] (large red square w/ small black square).

Notice that I made the 'w' window larger than 'cg', and colored it red. Even though I had drawn the image onto the window, which apparently maintained the differently-colored smaller square, for some reason everything (except the black square) is red.

If I just change the initial WindowCreate() to (w, 0, 0, 1, 1, 0, 0, 0), or move the WindowImageFromWindow() call to after the second WindowCreate(), it appears like [3] (large blue square w/ small green square and thin red border), which is the correct and expected view.

It seems like there is some issue with preloading an image into a 0x0 window, because the drawing operation itself didn't need to be moved in order to achieve the correct view. This seems strange to me, because the image doesn't depend on the window for its size, at least not until it's actually drawn onto the window. And preloading fonts into a 0x0 window works perfectly fine.

I could avoid this issue altogether by simply using a 1x1 dummy window for preloading resources, but the results of using 0x0 were strange and confusing enough that I'd rather make you aware of it.

[1]: http://img31.imageshack.us/img31/811/22047230.png
[2]: http://img13.imageshack.us/img13/2623/win1d.png
[3]: http://img13.imageshack.us/img13/5536/win2.png
Amended on Sat 12 Dec 2009 05:28 PM by Twisol
Australia Forum Administrator #1
The underlying bitmap used to hold the window data before it is drawn onto the screen is created by calling the Windows OS function CreateBitmap.

According to the help for CreateBitmap:


If an application sets the nWidth or nHeight parameters to zero, CreateBitmap returns the handle to a 1- by 1-pixel, monochrome bitmap.


Thus the colours you see are the best it can do in rendering your colour image in monochrome.

I can see a couple of options here:

  • Add a note to the help, that dummy windows should be at least 1x1 if you are planning to preload images.
  • Force the bitmap to be 1x1 in the case where you specify a 0x0 window, so the problem goes away. With luck, even if you accidentally draw it, the size will be considered the size you specify and not 1x1.

USA #2
I'm not sure I understand. The window I'm copying has nonzero dimensions, and this code from the CMiniWindow::ImageFromWindow function certainly appears to be using the source window's dimensions, not the dimensions of the window I'm preloading the image data into.


  // make new bitmap of appropriate size to hold image from other miniwindow
  CBitmap * pImage = new CBitmap;
  pImage->CreateCompatibleBitmap (&dc, pSrcWindow->m_iWidth, pSrcWindow->m_iHeight);

  // prepare to copy it
  CDC bmDC;
  bmDC.CreateCompatibleDC(&dc);
  CBitmap *pOldbmp = bmDC.SelectObject(pImage);

  // copy into our bitmap
  bmDC.BitBlt (0, 0, pSrcWindow->m_iWidth, pSrcWindow->m_iHeight, &pSrcWindow->dc, 0, 0, SRCCOPY); 
Australia Forum Administrator #3
Right. This code here creates a miniwindow, the important lines in bold:


// create (or re-create) a mini-window
void CMiniWindow::Create (long Left, long Top, long Width, long Height,
                          short Position, long Flags, 
                          COLORREF BackgroundColour)
  {
 
  m_Location.x           = Left            ;
  m_Location.y           = Top             ;
  m_iWidth               = Width           ;
  m_iHeight              = Height          ;
  m_iPosition            = Position        ;
  m_iFlags               = Flags           ;
  m_iBackgroundColour    = BackgroundColour;

  // get rid of old one if any
  if ((HBITMAP) m_Bitmap)
    {
    dc.SelectObject(m_oldBitmap);    // swap old one back
    m_Bitmap.DeleteObject ();
    }

  m_Bitmap.CreateBitmap (m_iWidth, m_iHeight, 1, GetDeviceCaps(dc, BITSPIXEL), NULL); 
  m_oldBitmap = dc.SelectObject (&m_Bitmap);
  dc.SetWindowOrg(0, 0);

  dc.FillSolidRect (0, 0, m_iWidth, m_iHeight, m_iBackgroundColour);

  m_bShow = false;

  // a newly created window has no hotspots
  DeleteAllHotspots ();

  } // end of MiniWindow::Create


This establishes the bitmap for the newly-created window. In the case of a 0x0 window that will be monochrome.

Now in the code you quote:


// make new bitmap of appropriate size to hold image from other miniwindow
  CBitmap * pImage = new CBitmap;
  pImage->CreateCompatibleBitmap (&dc, pSrcWindow->m_iWidth, pSrcWindow->m_iHeight);


The bitmap "to hold image from other miniwindow" is a *compatible* bitmap - compatible with the bitmap in the miniwindow (dc, which is a member variable of CMiniWindow). In this case, a monochrome one.
Amended on Sat 12 Dec 2009 08:23 PM by Nick Gammon
Australia Forum Administrator #4
Twisol said:

The window I'm copying has nonzero dimensions, and this code from the CMiniWindow::ImageFromWindow function certainly appears to be using the source window's dimensions, not the dimensions of the window I'm preloading the image data into.


It's not the size - the image you showed had the correct size, it is the number of bits per pixel.
USA #5
Ahhh, I see. Well, like I said, it's confusing enough that I thought I'd bring it up.


Quote:

Force the bitmap to be 1x1 in the case where you specify a 0x0 window, so the problem goes away.

Would this be a viable option? It seems it would be easiest to do, just ensure that even if you pass in dimensions less than 1, it always locks it back at 1.
Australia Forum Administrator #6
Fixed in version 4.45.

Now the internal bitmap is forced to be at least 1 x 1, so that, internally, it is a RGB image and not a monochrome one.

However the window, for display purposes, will still be 0 x 0 and thus would not be visible, were you to try to display it.
USA #7
Wonderful! Thanks Nick!