Уменьшить растровое изображение до требуемого размера - PullRequest
1 голос
/ 09 июня 2009

У меня есть растровое изображение большого размера (2000 x 2000), мне нужно уменьшить это растровое изображение до небольшого размера (150 x 150). Я написал код для него, но он не работает. Кто-нибудь может помочь в поиске проблемы? Проблема в том, что растровое изображение назначения просто пустое. Я выбираю неправильные DC? Я удостоверился, что и источник и места назначения правильны. После выполнения bitblt мне нужно сделать еще кое-что с целевым растровым изображением?

BOOL ReSizeBitmap(CBitmap *pBitmap, CBitmap *pNewBitmap)
{

    // Get new bitmap size
    BITMAP bmOld;
    if( !pBitmap->GetBitmap(&bmOld) )
    {
        return FALSE;
    }

    CRect rcPrev(0, 0, bmOld.bmWidth, bmOld.bmHeight);
    int newWidth  = 150;
    int newHeight = 150;

    if( newWidth < 1 || newHeight < 1 )
    {
        ::SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    BOOL bResult = FALSE;
    try
    {   
            CDC dcDest;
            CDC dcSource;

            dcSource.CreateCompatibleDC(NULL);
            dcDest.CreateCompatibleDC(NULL);

            CBitmap* pSourceOld = dcSource.SelectObject(pBitmap);
            CBitmap* pDestold = dcDest.SelectObject(pNewBitmap);

            if( !pNewBitmap->CreateCompatibleBitmap(
                &dcDest, newWidth, newHeight) )
            {

                return FALSE;
            }

            int oldStretchMode = dcDest.SetStretchBltMode(HALFTONE);

            bResult = dcDest.StretchBlt(
                0, 0, 150, 150,
                &dcSource, 0, 0, bmOld.bmWidth, bmOld.bmHeight,
                SRCCOPY);   
            dcDest.SetStretchBltMode(oldStretchMode);

            dcSource.SelectObject(pSourceOld);
            dcDest.SelectObject(pDestold);


        bResult = TRUE;
    }
    catch(CResourceException* /*e*/)
    {

    }

    return bResult;
}

Ответы [ 5 ]

1 голос
/ 09 июня 2009

Хорошо, даже если код работает, есть некоторая очистка.
RAII - одна из тех фраз, которые вам действительно нужны, когда вы работаете в MFC!

if( !pNewBitmap->CreateCompatibleBitmap(&dcDest, newWidth, newHeight) )
{
   return FALSE;
}

Когда вы возвращаете FALSE или возникает исключение, которое вы не вызвали

cSource.SelectObject(pSourceOld);
dcDest.SelectObject(pDestold); 

для очистки, прежде чем покинуть функцию.

Создайте небольшой вспомогательный класс для постоянной очистки, вам не нужно беспокоиться о операторах return или throw.

class SelectObjectAndCleanUp
{
    CDC& deviceContext;
    CBitmap *const oldSource;
public:
    SelectObjectCleanUp( CDC& deviceContext, CBitmap* source ) 
    : deviceContext(deviceContext),
      oldSource( deviceContext.SelectObject(source) ) {
    }

    ~SelectObjectCleanUp() {
            deviceContext.SelectObject(oldSource) 
    }
};

// use of the helper
SelectObjectCleanUp  sourceSelectionAndCleanup(dcSource, pBitmap );
SelectObjectCleanUp  destionationSelectionAndCleanup(dcDest, pNewBitmap );
1 голос
/ 09 июня 2009

Я не слишком знаком с C ++, но вы выбираете новое растровое изображение в свой новый DC до его создания? Кроме того, когда вы вызываете CreateCompatibleBitmap, я думаю, что вы хотите использовать ваш DC экрана (тот, который вы использовали для создания конечного DC), а не совместимый DC памяти. Итак, получите экран DC с GetDC и передайте его в CreateCompatibleDC и CreateCompatibleBitmap.

0 голосов
/ 09 июня 2009

Спасибо всем ребятам, которые подсматривали и предлагали решения, как бы то ни было, после некоторой отладки я обнаружил проблему. Вот решение !!!

CBitmap *SrcBmp;
HBITMAP hBmp;
hBmp= (HBITMAP)LoadImage( NULL, L"c:\\source.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
SrcBmp = CBitmap::FromHandle(hBmp);

BITMAP BmpInfo;
SrcBmp->GetBitmap(&BmpInfo);


CDC SrcDC;
SrcDC.CreateCompatibleDC(NULL);

CBitmap DestBmp;
DestBmp.CreateCompatibleBitmap(&SrcDC,150,150);

CDC DestDC;
DestDC.CreateCompatibleDC(NULL);

CBitmap *pOldBmp1 = SrcDC.SelectObject(SrcBmp);
CBitmap *pOldBmp2 = DestDC.SelectObject(&DestBmp);

DestDC.StretchBlt(0,0,150,150,&SrcDC,0,0,BmpInfo.bmWidth,BmpInfo.bmHeight,SRCCOPY);

CImage image;
image.Attach(DestBmp);
image.Save(_T("C:\\test.bmp"), Gdiplus::ImageFormatBMP);

SrcDC.SelectObject(pOldBmp1);
DestDC.SelectObject(pOldBmp2);
0 голосов
/ 09 июня 2009
  • Загрузка http://www.gdiwatch.com/, может показывать, где находится ошибка (ее также можно настроить для работы с vs 2008 - просто скопируйте ключи реестра вручную из каталогов vs2005 в vs2008)

  • Вы пытались выполнить CreateCompatibleBitmap () перед вызовом SelectObject ()?

  • Возвращает ли GetBitmap () нового растрового изображения правильный размер, т. Е. Действительное новое растровое изображение?

Остальные кажутся нормальными, я думаю, это должно сработать. Работает ли он с другими StretchBltModes?

0 голосов
/ 09 июня 2009

Существует отличная бесплатная библиотека изображений C ++ под названием CxImage , которая имеет открытый исходный код по лицензии zlib.

Не нужно изобретать велосипед.

...