Gönderen Konu: BMP Loader  (Okunma sayısı 7726 defa)

BMP Loader

« : 29.08.2005 20:26:11 »
Hızlı düğmeleri aç

anesthetic

İleti: 403

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://resident.tr-demoscene.info/
bmp dosyalarının içeriğini kolayca almayı anlatalım bakalım biz de, ufak da olsa bi katkımız olsun.

.bmp dosyaları iki struct (file header, bitmap header) ve iki arrayden oluşuyor (color index, color data). Çeşit çeşit bitmap dosyası olduğundan, bu verileri okuyup renkleri alan bi programın bol bol koda sahip olması gerekli. Ama bunlar winapi altında var zaten. İşte burda bu yükü winapi'ye yükleyip nasıl bitmapi okuturuz onu anlatacağım. (gdi plus'ta aynı işi yapan tek bi fonksiyon var sanırım. Belki normal gdi'da bile vardır ama bulamadım.)

Programımız dosya ismini alacak ve renkleri 24bit yerleştirdiği belleğin adresini dönecek. Aynı zamanda verilen integer adreslerine genişlik ve yüksekliği yazacak. Bitmap için handle, bitmap bilgisi için BITMAP structeı, bitmapi okumamıza yardım edecek device context için handle, bir kaç geçici integer ve belleği dolduracağımız yer için bir pointer gerekli.
Kod: [Seç]
unsigned char* LoadBitmapFromFile (TCHAR* szFileName, int *piWidth, int *piHeight)
{
     HBITMAP hBitmap;
     BITMAP  Bitmap ;
     HDC     hDC    ;

     unsigned int  iColor, x, y, iPos = 0;
     unsigned char *pcRGBArray           ;
İlk önce verilen dosya ismini kullanarak dosyamızı bitmap olarak alalım. Bunun için LoadImage fonksiyonunu kullanıyoruz, processlerden değil de dosyadan aldığımız bir çok parametre 0. Önemli olan dosya ismi ve bitmap olduğu. (LoadBitmap fonksiyonu resourcedan almak için kullanılıyor.)
Kod: [Seç]
hBitmap = LoadImage (NULL, szFileName, IMAGE_BITMAP, 0, 0,
                      LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if(hBitmap == NULL)
{
     MessageBox (NULL, TEXT("Dosya yüklenemedi."),
                 szFileName, MB_ICONERROR);
     return NULL;
}
Şimdi bitmapimizin genişlik ve yüksekliğini almak için GetObject fonksiyonunu kullanacağız. Bu fonksiyon bitmap handleı için BITMAP structeı dolduracak. Bitmap adlı structeımızın boyunu ve adresini yolladık mı o bize gerisini yapacak.
Kod: [Seç]
GetObject (hBitmap, sizeof (Bitmap), &Bitmap);
Yeni doldurulmuş structımızı okuyalım ve genişik, yükseklik bilgilerimizi yazalım:
Kod: [Seç]
*piWidth  = Bitmap.bmWidth;
*piHeight = Bitmap.bmHeight;
Sıradaki işimiz bitmapimizi analiz edip ekran moduna uygun hale getirmek. İlk önce mönitör ile uyumlu bir device context hazırlıyoruz. (CreateCompatibleDC başaramazsa NULL dönecektir isterseniz kontrol edebilirsiniz.) Daha sonra bu device contexti bitmap üzerinde kullanıyoruz.
Kod: [Seç]
hDC = CreateCompatibleDC (NULL);
SelectObject (hDC, hBitmap);
Artık bitmapimiz gdi fonksiyonları ile çizime hazır ama amacımız bu değil. Artık bitmapimize ait bir device contextimiz olduğuna göre istediğimiz pikseli GetPixel fonksiyonu ile görebiliriz. (SetPixel'le de yazabiliriz.) Şimdi renk bilgileri için yer alıp orayı dolduralım (GDI'ın renkleri 0xBBGGRR formatında tuttuğunu unutmadan). Her pikselde rengi integer olarak alıyoruz. 24bit renk arrayimiz için piksel adresinde R, G, B sırasıyla 3 byteı dolduruyoruz.
Kod: [Seç]
pcRGBArray = (unsigned char*)malloc ((*piWidth) * (*piHeight) * 3);
for (y = 0; y < (*piHeight); y++) for (x = 0; x < (*piWidth); x++)
{
     iColor = GetPixel (hDC, x, y);

     pcRGBArray[iPos++] =  iColor        & 0xFF;
     pcRGBArray[iPos++] = (iColor >>  8) & 0xFF;
     pcRGBArray[iPos++] = (iColor >> 16) & 0xFF;
}
Son olarak ortalığı toparlıyoruz:
Kod: [Seç]
DeleteObject (hDC)    ;
DeleteObject (hBitmap);
ve fonksiyondan çıkabiliriz:
Kod: [Seç]
    return pcRGBArray;
}

Kodun tamamı şöyle olacak:
Kod: [Seç]
unsigned char* LoadBitmapFromFile (TCHAR* szFileName, int *piWidth, int *piHeight)
{
     HBITMAP hBitmap;
     BITMAP  Bitmap ;
     HDC     hDC    ;

     unsigned int  iColor, x, y, iPos = 0;
     unsigned char *pcRGBArray          ;

     hBitmap = LoadImage (NULL, szFileName, IMAGE_BITMAP, 0, 0,
                           LR_LOADFROMFILE | LR_CREATEDIBSECTION);
     if(hBitmap == NULL)
     {
          MessageBox (NULL, TEXT("Dosya yüklenemedi."),
                      szFileName, MB_ICONERROR);
          return NULL;
     }

     GetObject (hBitmap, sizeof (Bitmap), &Bitmap);
     *piWidth  = Bitmap.bmWidth;
     *piHeight = Bitmap.bmHeight;

     hDC = CreateCompatibleDC (NULL);
     SelectObject (hDC, hBitmap);

     pcRGBArray = (unsigned char*)malloc ((*piWidth) * (*piHeight) * 3);

     for (y = 0; y < (*piHeight); y++) for (x = 0; x < (*piWidth); x++)
     {
          iColor = GetPixel (hDC, x, y);

          pcRGBArray[iPos++] =  iColor        & 0xFF;
          pcRGBArray[iPos++] = (iColor >>  8) & 0xFF;
          pcRGBArray[iPos++] = (iColor >> 16) & 0xFF;
     }

     DeleteObject (hDC)    ;
     DeleteObject (hBitmap);

     return pcRGBArray;
}
Son olarak bir noktaya da değinelim. LoadImage fonksiyonunun aldığı dosya isminde bi iki kriter gerekli (çoğu winapi fonksiyonunda olanlardan):
-Dosya sonu ve başında tırnak olmayacak
-Dizinleri ayırmak için / ya da \ (iki tane) kullanılacak.

Bi de monokrom ya da index color modda device context doğru hazırlanıyor mu deneyemedim ama 16bit renkte sorun yok gibi.

BMP Loader

« Yanıtla #1 : 30.08.2005 01:42:25 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
Güzel tutorial olmuş, ellerine sağlık. Daha önce de PCX yükletme anlatılmıştı yanılmıyorsam. Ben de Animated GIF anlatiim bir boş vaktimde atraksiyon olsun :)

BMP Loader

« Yanıtla #2 : 30.08.2005 01:43:45 »
Hızlı düğmeleri aç

skate

İleti: 5.245

A Sinner Scener
Çevrimdışı
  • Administrator
  • *****
  • Hero Member
    • Profili Görüntüle
    • http://www.akaydin.com/
Hatta şimdi hatırladım ben bir ara FLI (FLIC) shower yapmıştım ancak yalnızca ilk framei bastırmıştım :) 3ds studio dos zamanlarından kalma gereksiz bir anımdır :D

BMP Loader

« Yanıtla #3 : 19.03.2006 13:18:40 »
Hızlı düğmeleri aç

anesthetic

İleti: 403

Çevrimdışı
  • ****
  • Sr. Member
    • Profili Görüntüle
    • http://resident.tr-demoscene.info/
modlardan biri bu topici coding->pc'ye taşıyabilir mi? az önce lazım oldu. search'ü akıl edene kadar bulamadım :)