Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: bmp kuvan tallentaminen

Sivun loppuun

Lahdevesi [08.02.2020 02:17:20]

#

bmp-kuva luetaan koodilla:

void BitMapTest(void)
{
   HBITMAP valikko=LoadImage(NULL, "C:\\kuva.bmp", IMAGE_BITMAP,
   1024, 1024, LR_LOADFROMFILE);
   HDC src=CreateCompatibleDC(NULL);
   SelectObject(src, valikko);
   HDC dst=GetDC(hwnd);
   BitBlt(dst, 0, 0, 1024, 1024, src, 0, 0, SRCCOPY);
}

Nyt pelissä muokataan tuota kuvaa, mutta miten se tallennetaan?

Metabolix [08.02.2020 12:47:38]

#

Tähän löytyy hyvinkin koodeja esim. hakusanoilla WinAPI save BMP.

Onko jokin syy, miksi ylipäänsä käytät WinAPIa etkä jotain yksinkertaisempaa kirjastoa?

Lahdevesi [08.02.2020 20:47:51]

#

Metabolix kirjoitti:

(08.02.2020 12:47:38): Tähän löytyy hyvinkin koodeja esim...

Olen ohjelmoinut kaikki WinApilla, eikä noilla hakusanoilla löydy yksinkertaista koodiesimerkkiä, miten bmp tiedosto käytännössä tallennetaan kovalevylle. Voisiko täältä saada esimerkin funktiolle:

TallenaBMPtiedosto(char *tiedostonNimi, HDC hdc, HWND hwnd,
                   int leveys, int korkeus)
{
    // Talletettava 24-bittinen bmp tiedosto alkaa pisteestä (0, 0)
}

Tallennettava bmp tiedosto on RGB väreissä.

Teen fraktaalizoomausta. Minun pahin ongelma on, etten vielä osaa hyvin englanninkieltä.

Metabolix [08.02.2020 20:51:51]

#

Viestini ensimmäinen linkki vie suoraan koodiin, joten miten on mahdollista, että et löydä? Koodi on kyllä erittäin pitkä ja hankala. Jos ei ole jotenkin aivan erityistä kiinnostusta juuri WinAPI:n käyttöön, olisi viisasta tehdä ohjelma jollain helpommalla työkalulla. Sopiva työkalu riippuu toki ohjelmasta, mutta useimpiin ohjelmiin on varmasti olemassa helpompia vaihtoehtoja kuin suora WinAPI:n käyttö.

jalski [08.02.2020 21:11:17]

#

Lahdevesi kirjoitti:

Olen ohjelmoinut kaikki WinApilla, eikä noilla hakusanoilla löydy yksinkertaista koodiesimerkkiä, miten bmp tiedosto käytännössä tallennetaan kovalevylle.

Jos etsit muutaman rivin esimerkkiä WinApilla, et löydä sellaista vaan pääset kirjoittelemaan BITMAPFILEHEADER:in, täyttelemään BITMAPINFOHEADER:in ja muuta mukavaa...

Helpointa olisi varmaan käyttää GDI+:saa hoitamaan homma. Ei muistaakseni vaadi kauhean montaa riviä koodia.

Lahdevesi [09.02.2020 01:34:04]

#

Metabolix kirjoitti:

(08.02.2020 20:51:51): Viestini ensimmäinen linkki vie suoraan koodiin...

Minulla on mozilla firefox. Voisiko se ehdottaa jotain toista sivua ensimmäiseksi, mitä sivua tarkoitat, koska sivulla ei ole mitään järkevää vihjettä?

Metabolix [09.02.2020 17:04:32]

#

Väännetään nyt vielä rautalangasta:

Metabolix kirjoitti:

Tähän löytyy hyvinkin ⇒ ⇒ ⇒ koodeja ⇐ ⇐ ⇐ esim. hakusanoilla WinAPI save BMP.

Yllä nuolilla merkitty linkki vie suoraan kohteeseen. Olet sikäli oikeassa, että sivulta ei löydy ”järkevää vihjettä” vaan koko pitkä tallennuskoodi, jota pitää sitten vielä osata käyttää.

jalski [09.02.2020 17:40:54]

#

Itse olen joskus käyttänyt GDI+ Flat api:a kun piti saada kuva tallennettua png formaattiin.

Muistaakseni menee jotenkin:

GdiplusStartup
GdipCreateFromHDC
GdipCreateBitmapFromGraphics
GdipSaveImageToFile
GdiplusShutdown

Parametrit noihin saat hakea netin kautta itse...

rannekello [12.02.2020 10:35:22]

#

Onpa mukavaa, että minäpä osaan, muta sinä et, häh, häh, hää. Onko se nyt ihan ylivoimaista kopioida funktion sisältö raameihin:

/***********************************************************************
* BMP kuva kirjoitetaan tiedostonNimi -binääritiedostoon               *
* leveys on BMP kuvan leveys alkaen positiosta 0                       *
* korkeus on BMP kuvan korkeus alkaen positiosta 0                     *
* bittitarkkuus voi olla 1, 2, 4, 8, 16 ja 24-bittinen RGB-värisyvyys. *
* Itse käytän 24-bittistä värisyvyyttä.                                *
***********************************************************************/
void saveBMP(char *tiedostonNimi, int leveys, int korkeus, int bittitarkkuus)

Ei minun pelin oleellisin asia ole BMP-tiedoston kirjoittaminen kovalevylle, mutta se on oleellinen apufunktio.

Varsinkin, jos tietää, millainen tuo funktion sisältö on, ja jos se käy suunnilleen kopioi - liitä toiminnolla, ihmettelen suuresti tämän sivuston tarkoitusta.

Mitä järkeä on kysyä yhtään mitään ohjelmointiongelmiin liittyvää, jos vastauksena on pelkkiä ympäripyöreitä linkkejä, että kaiva se oleellinen asia sieltä sotkun seasta.

Tekisi mieli sanoa ruma sana. Ja miksi koneen boottauksen jälkeen joutuu aina luomaan uuden käyttäjätunnuksen. Varmaan siksi, että tunnus vaatii niin monimutkaisen salasanan.

Grez [12.02.2020 15:02:44]

#

rannekello kirjoitti:

Varsinkin, jos tietää, millainen tuo funktion sisältö on, ja jos se käy suunnilleen kopioi - liitä toiminnolla, ihmettelen suuresti tämän sivuston tarkoitusta.

Mistä päättelet että kenelläkään täällä vastanneella olisi ollut käytössään jotain kuvaamasi tyylistä funktiota?

Ensinnäkin voi olla ettei täällä ole lisäksesi muita masokisteja (jotka siis haluaisivat koodata suoraan WinAPIlla)

Toisekseen vaikka joku olisi jotain koodannutkin niin on aika epätodennäköistä, että kellään sattuisi vaan olemaan koodi joka kopioi näyttöpinnalta 0,0 - 1023,1023 alueelta kuvan bittikartaksi ja tallentaa sen. (Kuten tarpeesi alkuperäisessä viestissä kuvailit)

Ohessa on netistä löytämäni esimerkki, joka tallentaa koko näytön bitmapiksi. Siitä luulisi olevan aika helppo soveltaa: (Kuten ehkä huomaat niin tuossa on mukana ne Metabolixin aikaisemmin laittamat koodit lähes sellaisinaan. Tässä vaan on vielä lisäksi käytännön esimerkki miten niitä käytetään)

#include <Windows.h>
#include <stdio.h>
#include <assert.h>

/* forward declarations */
PBITMAPINFO CreateBitmapInfoStruct(HBITMAP);
void CreateBMPFile(LPTSTR pszFile, HBITMAP hBMP);
int main(int argc, char **argv);

PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
{
    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD    cClrBits;

    // Retrieve the bitmap color format, width, and height.
    assert(GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp));

    // Convert the color format to a count of bits.
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
    if (cClrBits == 1)
        cClrBits = 1;
    else if (cClrBits <= 4)
        cClrBits = 4;
    else if (cClrBits <= 8)
        cClrBits = 8;
    else if (cClrBits <= 16)
        cClrBits = 16;
    else if (cClrBits <= 24)
        cClrBits = 24;
    else cClrBits = 32;

    // Allocate memory for the BITMAPINFO structure. (This structure
    // contains a BITMAPINFOHEADER structure and an array of RGBQUAD
    // data structures.)

     if (cClrBits < 24)
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER) +
                    sizeof(RGBQUAD) * (1<< cClrBits));

     // There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel

     else
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER));

    // Initialize the fields in the BITMAPINFO structure.

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = bmp.bmWidth;
    pbmi->bmiHeader.biHeight = bmp.bmHeight;
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
    if (cClrBits < 24)
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);

    // If the bitmap is not compressed, set the BI_RGB flag.
    pbmi->bmiHeader.biCompression = BI_RGB;

    // Compute the number of bytes in the array of color
    // indices and store the result in biSizeImage.
    // The width must be DWORD aligned unless the bitmap is RLE
    // compressed.
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
                                  * pbmi->bmiHeader.biHeight;
    // Set biClrImportant to 0, indicating that all of the
    // device colors are important.
     pbmi->bmiHeader.biClrImportant = 0;
     return pbmi;
 }

void CreateBMPFile(LPTSTR pszFile, HBITMAP hBMP)
 {
     HANDLE hf;                 // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    LPBYTE lpBits;              // memory pointer
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer
    DWORD dwTmp;
    PBITMAPINFO pbi;
    HDC hDC;

    hDC = CreateCompatibleDC(GetWindowDC(GetDesktopWindow()));
    SelectObject(hDC, hBMP);

    pbi = CreateBitmapInfoStruct(hBMP);

    pbih = (PBITMAPINFOHEADER) pbi;
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

    assert(lpBits) ;

    // Retrieve the color table (RGBQUAD array) and the bits
    // (array of palette indices) from the DIB.
    assert(GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
        DIB_RGB_COLORS));

    // Create the .BMP file.
    hf = CreateFile(pszFile,
                   GENERIC_READ | GENERIC_WRITE,
                   (DWORD) 0,
                    NULL,
                   CREATE_ALWAYS,
                   FILE_ATTRIBUTE_NORMAL,
                   (HANDLE) NULL);
    assert(hf != INVALID_HANDLE_VALUE) ;

    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
    // Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
                 pbih->biSize + pbih->biClrUsed
                 * sizeof(RGBQUAD) + pbih->biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;

    // Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
                    pbih->biSize + pbih->biClrUsed
                    * sizeof (RGBQUAD);

    // Copy the BITMAPFILEHEADER into the .BMP file.
    assert(WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
        (LPDWORD) &dwTmp,  NULL));

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    assert(WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
                  + pbih->biClrUsed * sizeof (RGBQUAD),
                  (LPDWORD) &dwTmp, ( NULL)));

    // Copy the array of color indices into the .BMP file.
    dwTotal = cb = pbih->biSizeImage;
    hp = lpBits;
    assert(WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL));

    // Close the .BMP file.
     assert(CloseHandle(hf));

    // Free memory.
    GlobalFree((HGLOBAL)lpBits);
}

int main(int argc, char **argv)
{
    HWND hwnd;
    HDC hdc[2];
    HBITMAP hbitmap;
    RECT rect;

    hwnd = GetDesktopWindow();
    GetClientRect(hwnd, &rect);
    hdc[0] = GetWindowDC(hwnd);
    hbitmap = CreateCompatibleBitmap(hdc[0], rect.right, rect.bottom);
    hdc[1] = CreateCompatibleDC(hdc[0]);
    SelectObject(hdc[1], hbitmap);

    BitBlt (
        hdc[1],
        0,
        0,
        rect.right,
        rect.bottom,
        hdc[0],
        0,
        0,
        SRCCOPY
    );

    CreateBMPFile("bitmap.bmp", hbitmap);
    return 0;
}

rannekello kirjoitti:

Mitä järkeä on kysyä yhtään mitään ohjelmointiongelmiin liittyvää, jos vastauksena on pelkkiä ympäripyöreitä linkkejä, että kaiva se oleellinen asia sieltä sotkun seasta.

Sille ei varmaan hirveästi mitään voi, että puhtaalla WinAPIlla koodatessa yksinkertaisenkin asian tekeminen on enemmän tai vähemmän sotku.

Metabolixin linkkaamalla sivulla oli 138 riviä koodia (jonka tarvitset kokonaan) ja lisäksi noin 12 riviä tekstiä. Koodit oli vielä laatikoissa joiden kulmissa oli "Copy" panikkeet. Jos se koodi "kaivaminen" sieltä tosiaan oli ihan ylivoimaista niin aika paljon kädestä pitämistä tarvitset.

vesikuusi [12.02.2020 15:06:01]

#

rannekello kirjoitti:

Onpa mukavaa, että minäpä osaan, muta sinä et, häh, häh, hää. Onko se nyt ihan ylivoimaista kopioida funktion sisältö raameihin:

Minusta ei ole kohtuutonta, että porukka ei jaksa alkaa tehdä sinun hommaasi puolestasi, eli soveltaa tuolta linkistä löytyvää koodia sinun käyttötarkoitukseesi. Sellainen on triviaalia, mutta työlästä eikä tuo juurikaan lisäarvoa tänne foorumille.

Metabolixin vastaus oli oikein hyvä, hän osoitti juuri siihen resurssiin jota tarvitset toteuttaaksesi tallennuksen ja lisäksi mainitsi, että homman voi tehdä helpomminkin. Ei foorumin tarkoitus ole tehdä sinulle koodejasi valmiiksi.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta