kgg124 Ответов: 2

Как получить данные байтового массива из gdiplus:: bitmap ?


Всем привет.
Я хочу получить данные массива байтов (данные изображения) из Gdiplus::Bitmap.
Поэтому я набрал следующий код.

bool CMyImage::GetImagePointer(BYTE* pBuffer)
{
//Gdiplus::Bitmap* m_pBmp; defined.
	PixelFormat format;
	format = m_pBmp->GetPixelFormat();
	int bpp = GetPixelFormatSize(format);
	int w = m_pBmp->GetWidth();
	int h = m_pBmp->GetHeight();
	int size = w*h*bpp/8;

	BitmapData data;
	Rect rect(0,0,w,h);
	m_pBmp->LockBits(&rect,ImageLockModeRead,format,&data);

	BYTE* pSrcPointer = (BYTE*)data.Scan0;
	BYTE* pDstPointer = pBuffer;
	
	int imageRowSize = w*bpp/8;
	for ( int i=0; i<h; i++ )
	{
		memcpy( pDstPointer, pSrcPointer, imageRowSize );
		pSrcPointer += w;
		pDstPointer += imageRowSize;
	}
	
	m_pBmp->UnlockBits(&data); 

	return true;
}


(Вопрос)
Но если размер ширины изображения (байтового массива)не кратен 4, растровое изображение не исправляет выравнивание.

В чем причина?

Пожалуйста, посоветуйте мне.

Спасибо.

Что я уже пробовал:

Если он изменяется следующим образом, выравнивание изображения будет правильным.
Но 1 строка в самом низу растрового изображения-это не данные.

bool CMyImage::GetImagePointer(BYTE* pBuffer)
{
//Gdiplus::Bitmap* m_pBmp; defined.
	PixelFormat format;
	format = m_pBmp->GetPixelFormat();
	int bpp = GetPixelFormatSize(format);
	int w = m_pBmp->GetWidth();
	int h = m_pBmp->GetHeight();
	int size = w*h*bpp/8;

	BitmapData data;
	Rect rect(0,0,w,h);
	m_pBmp->LockBits(&rect,ImageLockModeRead,format,&data);

        memcpy(pBuffer, (BYTE*)data.Scan0, size);
        /*
	BYTE* pSrcPointer = (BYTE*)data.Scan0;
	BYTE* pDstPointer = pBuffer;
	
	int imageRowSize = w*bpp/8;
	for ( int i=0; i<h; i++ )
	{
		memcpy( pDstPointer, pSrcPointer, imageRowSize );
		pSrcPointer += w;
		pDstPointer += imageRowSize;
	}
        */
	
	m_pBmp->UnlockBits(&data); 

	return true;
}

2 Ответов

Рейтинг:
1

Jochen Arndt

То Класс BitmapData (Windows)[^] обеспечивает Stride член, который содержит количество байтов в строке.

Используйте это вместо того, чтобы вычислять его. Вы также добавили w к pSrcPointer вместо размера строки:

int srcRowSize = std::abs(data.Stride);
// Which size to use for the destination depends on your usage.
// When calculating you must adjust for odd results
int imageRowSize = w*bpp/8;
if ((w*bpp) % 8)
    imageRowSize++;
for (int i=0; i<h; i++ )
{
    memcpy( pDstPointer, pSrcPointer, imageRowSize );
    // Add srcRowSize here instead of w
    //pSrcPointer += w;
    pSrcPointer += srcRowSize;
    pDstPointer += imageRowSize;
}

При копировании всех битов изображения сразу вы получаете размер по:
int size = data.Height * std::abs(data.Stride);


Рейтинг:
0

CPallini

Цитата:
В чем причина?
Это называется шаг.
От DIBs и их использование в MSDN[^]:


bisizeimage с Содержит размер собственно растрового изображения в байтах или значение 0. Значение 0 указывает на то, что DIB имеет размер по умолчанию. Вычислить размер растрового изображения несложно:
biSizeImage = ((((biWidth * biBitCount) + 31) &
~31) >> 3) * biHeight; 

Сумасшедшие округления и сдвиги объясняют выравнивание растрового изображения по DWORD в конце каждой строки сканирования. Когда значение ненулевое, это поле сообщает приложению, сколько места для хранения требуется битам DIB. Поле biSizeImage действительно становится полезным при работе с растровым изображением RLE, размер которого зависит от того, насколько хорошо было закодировано растровое изображение. Если растровое изображение RLE должно передаваться по кругу, поле biSizeImage является обязательным.