Устаревший код C ++ не отображает растровое изображение под Windows 10 - PullRequest
0 голосов
/ 27 сентября 2019

Мне нужно получить какой-нибудь устаревший (XP) код MFC, работающий под Windows 10. Он отлично работает под Windows 7. Я не пробовал никаких других версий.

Идея состоит в том, что в буфере естьпамять, которая содержит значения пикселей изображения в RGB.Затем для отображения изображения на экране оно преобразуется в растровое изображение и затем копируется в DC.

Это функция, которая отображает объект на экране.Кажется, что это работает, но тогда на экране ничего не появляется, кроме белого поля.

(комментарии уже были там! Кто-то, должно быть, тоже повеселился с этим!)

WORD* CFBuffer24::getBitmap(int nBitsPerPixel)
{
    // check operation is valid
    ASSERT(m_pFB[RED] && m_pFB[GREEN] && m_pFB[BLUE]);

    if (nBitsPerPixel == 24)
    {
        if(NULL == m_pbm24)
            m_pbm24 = new UCHAR[((m_fbSize.cx*3+3) & ~3)*m_fbSize.cy];
        ASSERT(m_pbm24);
        UCHAR* rptr = m_pFB[RED]->getPointer(0,0);
        UCHAR* gptr = m_pFB[GREEN]->getPointer(0,0);
        UCHAR* bptr = m_pFB[BLUE]->getPointer(0,0);
        UCHAR* sptr = m_pbm24;
        if (m_dGamma == 1.0)
        {
            for (int i = 0; i < m_fbSize.cx*m_fbSize.cy; i++, rptr++, gptr++, bptr++)
            {
                // Assumes 24bit display ie. B R G format
                *sptr++ = *bptr; 
                *sptr++ = *gptr; 
                *sptr++ = *rptr;
            }
        }
        else
        {
            UCHAR* wLUT = new UCHAR[256];
            for (int i = 0; i < 256; i++)
            {
                int val = (int) (255.0 * pow((double) i / 255.0,1.0/m_dGamma) + 0.5);
                if (val > 255)
                    val = 255;
                wLUT[i] = UCHAR(val);
            }
            for (i = 0; i < m_fbSize.cx*m_fbSize.cy; i++, rptr++, gptr++, bptr++)
            {
                // Assumes 16bit display ie. 5R:6G:5B format
                *sptr++ = wLUT[*bptr]; 
                *sptr++ = wLUT[*gptr]; 
                *sptr++ = wLUT[*rptr];
            }
            delete [] wLUT;
        }
        return((WORD*)m_pbm24);
    }
    // 
    if (nBitsPerPixel == 16)
    {
        if(NULL == m_pbm16)
            m_pbm16= new WORD[((m_fbSize.cx*2+3) & ~3)*m_fbSize.cy];
        ASSERT(NULL != m_pbm16);

        UCHAR* rptr = m_pFB[RED]->getPointer(0,0);
        UCHAR* gptr = m_pFB[GREEN]->getPointer(0,0);
        UCHAR* bptr = m_pFB[BLUE]->getPointer(0,0);
        WORD* sptr = m_pbm16;
        if (m_dGamma == 1.0)
        {
            for (int i = 0; i < m_fbSize.cx*m_fbSize.cy; i++, rptr++, gptr++, bptr++)
            {
                // Assumes 16bit display ie. 5R:6G:5B format
                *sptr++ = (WORD) ((((WORD)*bptr>>3)&0x001F) | 
                        (((WORD)*gptr<<3)&0x07E0) | 
                        (((WORD)*rptr<<8)&0xF800));
            }
        }
        else
        {
            WORD* wLUT = new WORD[256];
            for (int i = 0; i < 256; i++)
            {
                wLUT[i] = (WORD) (255.0 * pow((double) i / 255.0,1.0/m_dGamma) + 0.5);
                if (wLUT[i] > 255)
                    wLUT[i] = 255;
            }
            for (i = 0; i < m_fbSize.cx*m_fbSize.cy; i++, rptr++, gptr++, bptr++)
            {
                // Assumes 16bit display ie. 5R:6G:5B format
                *sptr++ = (WORD) (((wLUT[*bptr]>>3)&0x001F) | 
                        ((wLUT[*gptr]<<3)&0x07E0) | 
                        ((wLUT[*rptr]<<8)&0xF800));
            }
            delete [] wLUT;
        }
        return(m_pbm16);
    }
    // Bits per pixel must be wrong
    return 0;
}

bool CImDisplay::CheckDisplaySize(CSize Imsize)
{
    if (Imsize != m_Imsize)     // resize the buffer
    {
        m_Imsize = Imsize;
        // check the display capabilities
        CDC* pDC;
        pDC = m_pWnd->GetDC();
        //Get the display capabilities
        m_nBitPlanes = pDC->GetDeviceCaps( PLANES );    //Usually 1
        m_nBitsPerPixel = pDC->GetDeviceCaps( BITSPIXEL );//Usually number of colours
        m_pWnd->ReleaseDC(pDC);
        if( m_nBitsPerPixel != 16 && m_nBitsPerPixel != 24 )
        {
            ::MessageBox(::GetActiveWindow(),"Video mode is not compatable with\noutput resolution. Change Screen/Settings to 16 or 24 bits.","Unable to Display image", MB_ICONSTOP);
            return false;
        }
        if (m_pBuf != 0)
            delete [] m_pBuf;
        m_pBuf = new UCHAR[m_Imsize.cx * m_Imsize.cy * m_nBitsPerPixel / 8];
        if( !m_Map.CreateBitmap( m_Imsize.cx, m_Imsize.cy, m_nBitPlanes, m_nBitsPerPixel, m_pBuf ) )
            ::MessageBox(::GetActiveWindow(),"Can not create bitmap","Unable to Display image", MB_ICONSTOP);
    }
    return true;
}

void CImDisplay::Display(CFBuffer24* Image, CRect subRect)
{
    CheckWindowPointer();
    // Build the bastard bitmap
    CSize imsize = Image->getBufferSize();
    CheckDisplaySize(imsize);

    // Write the Data to the Bit map
    // Copies the image from our 24bit buffer into a bitmap and returns the pointer to the bitmap
    DWORD dRet = m_Map.SetBitmapBits(imsize.cx*imsize.cy*m_nBitsPerPixel/8, Image->getBitmap(m_nBitsPerPixel) );
    //Draw the bastard thing
    CDC* pDC;
    pDC = m_pWnd->GetDC();
    CDC MemDC;
    MemDC.CreateCompatibleDC( pDC );
    CBitmap *pOldBitmap  = MemDC.SelectObject( &m_Map );
    pDC->SetStretchBltMode(COLORONCOLOR);   // this gets the colours looking correct
    pDC->StretchBlt(  m_Location.TopLeft().x, m_Location.TopLeft().y, 
                            m_Location.Width(), m_Location.Height(),
                            &MemDC, imSubRect.left, imSubRect.top, 
                            imSubRect.Width(), imSubRect.Height(), SRCCOPY  );
    MemDC.SelectObject( pOldBitmap );               //Release the object
    m_pWnd->ReleaseDC(pDC);
}

Я запускаю программу в совместимом 16-битном цвете на Windows 10. Это так, что она действительно будет работать, и в противном случае она будет работать нормально.

Мне удалось получить что-то для отображения на Windows 10, когда у меня естьиспользовал CreateCompatibleBitmap () вместо CreateBitmap (), но все цвета искажены.На Windows 7 у них все хорошо.Возможно, это ключ, но я не могу понять, что это значит.

1 Ответ

1 голос
/ 27 сентября 2019

Ваш код может неправильно рассчитать требуемое пространство для растровых изображений, если ширина не кратна 4. Это должно быть required_size = ( (width * bits_per_pixel / 8 + 3) & ~3 ) * height.

Если CFBuffer24 правильно обрабатывает шаг (байт на строку), вы можете растянутьнепосредственно перед контекстом устройства:

void CImDisplay::Display(CFBuffer24* Image, CRect subRect)
{
    CheckWindowPointer();

    CDC* pDC = m_pWnd->GetDC();

    m_nBitPlanes = pDC->GetDeviceCaps( PLANES );    //Usually 1
    m_nBitsPerPixel = pDC->GetDeviceCaps( BITSPIXEL );//Usually number of colours
    if( m_nBitsPerPixel != 16 && m_nBitsPerPixel != 24 && m_nBitsPerPixel != 32 )
    {
        ::MessageBox(::GetActiveWindow(),"Video mode is not compatable with\noutput resolution. Change Screen/Settings to 16 or 24 bits.","Unable to Display image", MB_ICONSTOP);
        return;
    }

    if ( m_nBitsPerPixel == 32 )
        m_nBitsPerPixel = 24;

    m_Imsize = Image->getBufferSize();

    // Bitmap rows are aligned to multiplies of 4 bytes
    int stride = (m_Imsize.cx * m_nBitsPerPixel / 8 + 3) & ~3;

    BITMAPINFO  bi =
    {
        sizeof( BITMAPINFOHEADER ),
        stride,
        -m_Imsize.cy,    // If bitmap looks upside down remove minus
        1,
        m_nBitsPerPixel,
        BI_RGB,
        0,
        0,
        0,
        0,
        0
    };

    pDC->SetStretchBltMode(COLORONCOLOR);

    ::StretchDIBits(
            pDC,
            m_Location.TopLeft().x,
            m_Location.TopLeft().y,
            m_Location.Width(),
            m_Location.Height(),
            // !!!! I don't know what imSubRect is. Is it related to subRect?
            imSubRect.left,
            imSubRect.top,
            imSubRect.Width(),
            imSubRect.Height(),
            Image->getBitmap(m_nBitsPerPixel),
            &bi,
            DIB_RGB_COLORS,
            SRCCOPY );

    m_pWnd->ReleaseDC(pDC);
}

Приведенный выше код оставляет преобразование из 24 до 32 бит в StretchDIBits.Все должно быть в порядке производительности.В качестве альтернативы вы можете реализовать 32-битный регистр в CFBuffer24.

...