No zrobiłem sam:
Odczyt pikseli z dowolnego skmopresowanego obrazka w C++ WinAPI GDI
Oto dwie procedury:
- int LoadPictureFile(LPCTSTR szFile) -ładuje obraz** jpg/png/gif** itp. do LPPICTURE gpPicture; //IPicture*
- int ZapiszObrazDoPlikuRAWB(LPPICTURE pPicture, TCHAR *NazwaPliku) //zapisuje do pliku piksele z obrazu Picture w postaci RGB RGB RGB... w odpowiedniej kolejności
// Wczytuje plik do IStream. Ładuje obraz do gpPicture
int LoadPictureFile(LPCTSTR szFile)
{
//---open file
HANDLE hFile = CreateFile(szFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); //If the function fails, the return value is INVALID_HANDLE_VALUE
if (INVALID_HANDLE_VALUE == hFile) {MSGBlad(ghWnd, L"Nie można otworzyć pliku do czytania."); return -1;} //_ASSERTE(INVALID_HANDLE_VALUE != hFile);
//---get file size
DWORD dwFileSize = GetFileSize(hFile, NULL); //If the function fails and lpFileSizeHigh is NULL, the return value is INVALID_FILE_SIZE
if (INVALID_FILE_SIZE == dwFileSize) {MSGBlad(ghWnd, L"Nie można pobrać rozmiaru pliku."); return -2;} //_ASSERTE(-1 != dwFileSize);
//---alloc memory based on file size
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
if (NULL == hGlobal) {MSGBlad(ghWnd, L"Nie można zaalokować pamięci na plik."); return -3;} //_ASSERTE(NULL != hGlobal);
//[...] a co ze zwolnieniem pamięci!???
LPVOID pvData = GlobalLock(hGlobal);
if (NULL == pvData) {MSGBlad(ghWnd, L"Problem: GlobalLock()."); return -4;} //_ASSERTE(NULL != pvData); GlobalFree(hGlobal)
//---read file and store in global memory
DWORD dwBytesRead = 0;
BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
if (FALSE == bRead) {MSGBlad(ghWnd, L"Problem z odczytem pliku."); return -5;} //_ASSERTE(FALSE != bRead); GlobalFree(hGlobal)
GlobalUnlock(hGlobal);
CloseHandle(hFile);
//---create IStream* from global memory
LPSTREAM pstm = NULL;
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm); //SUCCEEDED(Status) == ((HRESULT)(Status) >= 0)
if (!SUCCEEDED(hr) || !pstm) {MSGBlad(ghWnd, L"Problem z CreateStreamOnHGlobal()."); return -5;} //_ASSERTE(SUCCEEDED(hr) && pstm); GlobalFree(hGlobal)
//---Create IPicture from image file
if (gpPicture) gpPicture->Release();
hr = ::OleLoadPicture(pstm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&gpPicture);
if (!SUCCEEDED(hr) || !gpPicture) {MSGBlad(ghWnd, L"Problem z odczytem pliku."); return -6;} //_ASSERTE(SUCCEEDED(hr) && gpPicture); GlobalFree(hGlobal);
pstm->Release();
//GlobalFree(hGlobal); // 16Bit Windows Needs This (32Bit - Automatic Release)
//InvalidateRect(ghWnd, NULL, TRUE); //odśwież okno
return 0; //wsz. ok
}
//---------------------------------------------------------------------------
int ZapiszObrazDoPlikuRAWB(LPPICTURE pPicture, TCHAR *NazwaPliku) //zapisuje do pliku RAWB piksele z obrazu Picture
{//używa ghWnd = CreateWindow() - uchwyt do głównego okna ale można użyć NULL
HDC hdc = GetDC(ghWnd); //hwnd; Działa z ghWnd i NULL.
HDC hdcMem = CreateCompatibleDC(hdc); //hdc; Tworzy HDC kompatybilny z podanym
//..w większości przypadków nie musimy podawać tego hdc jako argumentu; wtedy funkcja utworzy HDC kompatybilne z "bieżącym ekranem aplikacji"
HBITMAP hBitmap;
if (S_OK != pPicture->get_Handle((OLE_HANDLE FAR *)&hBitmap)) //pobranie uchwytu bitmapy z Picture
{ MSGBlad(ghWnd, L"Nie mogę dostać bitmap handle z picture.");
return -1;
}
if (S_OK != gpPicture->SelectPicture(hdcMem, NULL, NULL)) //Selects a bitmap picture into a given device context, and returns the device context in which the picture was previously selected
{ MSGBlad(ghWnd, L"Problem z SelectPicture().");
return -2;
}
//Pobierz width i height picture
long hmWidth, hmHeight; //wielkie rozmiary: Dla obrazu 211x312 => 5583x8255
pPicture->get_Width(&hmWidth);
pPicture->get_Height(&hmHeight);
//convert himetric to pixels
int nWidth = MulDiv(hmWidth, GetDeviceCaps(hdc, LOGPIXELSX), HIMETRIC_INCH); //MulDiv(a,b,c)=a*b/c ;hmWidth; daje wielkie powiększenie
int nHeight = MulDiv(hmHeight, GetDeviceCaps(hdc, LOGPIXELSY), HIMETRIC_INCH);
//---
BITMAPINFO bi; BOOL bRes;
int RozmiarBuf = nWidth * 4 * nHeight;
//Bitmap header
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = nWidth;
bi.bmiHeader.biHeight = nHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = RozmiarBuf;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
//Alokacja Bufora na piksele
unsigned char *Bufor = new unsigned char[RozmiarBuf]; //bo 4 bajty na piksel
//Get the all scanline. Don't use getPixel and SetPixel.It's very slow.
bRes = GetDIBits(hdcMem, //HDC hdc
hBitmap, //HBITMAP hbmp
0, //UINT uStartScan
nHeight, //UINT cScanLines
Bufor, //out: PVOID lpvBits
&bi, //LPBITMAPINFO lpbi,
DIB_RGB_COLORS); //UINT uUsage
ReleaseDC(ghWnd, hdc); //zwalniam HDC okna, po którym rysowałem, bo było GetDC(). Tak!
//DeleteDC(hdcMem); //kasowanie hdc, tylko Zawsze po SelectObject(hMemDC,hOldBitmap). Tu NIE, bo nie narysuje obrazu!!
//===Zapis do pliku uzyskanych pikseli
FILE *plik; //= _wfopen_s(NazwaPliku, _T("wb")); //zapis, binary; errno_t err;
_wfopen_s(&plik, NazwaPliku, _T("wb")); //zapis, binary; if( != 0) błąd
if (!plik)
{ MessageBoxEx(ghWnd, L"Nie można otworzyć do zapisu pliku.", L"Błąd", MB_OK | MB_ICONINFORMATION, LANG_POLISH); return -4;
}
int x,y,z,w;
//for (i=0; i < nWidth*4*nHeight; i += 4) fwrite(buf+i, 3, 1, plik); //od końca; ale tak będzie obraz odwrócony lewo-prawo
for (y=0; y < nHeight; y++)
{w = (nHeight-1-y) * nWidth; //linie od dołu do góry
for (x=0; x < nWidth; x++)
{ z = (w + x)*4; //długość linii == nWidth*4
putc(Bufor[z+2], plik); //R
putc(Bufor[z+1], plik); //G
putc(Bufor[z], plik); //B
}
}
//---
fclose(plik);
delete[] Bufor;
return 0; //wsz. ok
}