'MFC/Bitmap'에 해당되는 글 9건

  1. 2013.08.16 핸들변환
  2. 2013.08.16 Storing an Image
  3. 2013.08.16 Bitmap.h
  4. 2013.08.16 Bitmap.cpp
  5. 2013.08.09 리소스에서 BMP 이미지 불러오기
  6. 2013.08.08 Writing a window image to a BMP file
  7. 2013.08.08 Converting DDB to DIB
  8. 2013.08.08 memory dc to bitmap file
  9. 2013.08.08 Bitmap Save

핸들변환

MFC/Bitmap 2013. 8. 16. 14:36

HBITMAP hBmp = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE (IDB_BITMAP1));

---------------------------------------

CImage img;

img.LoadFromResource(AfxGetInstanceHandle(), IDB_BITMAP1);
img.Save("Sample.bmp", Gdiplus::ImageFormatBMP);

---------------------------------------

 

 

 

'MFC > Bitmap' 카테고리의 다른 글

Storing an Image  (0) 2013.08.16
Bitmap.h  (0) 2013.08.16
Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Posted by 곰돌이짱
,

Storing an Image

MFC/Bitmap 2013. 8. 16. 13:18

http://msdn.microsoft.com/en-us/library/windows/desktop/dd145170%28v=vs.85%29.aspx

 

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

    // Retrieve the bitmap color format, width, and height.  
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) 
        errhandler("GetObject", hwnd); 

    // 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(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, 
                  HBITMAP hBMP, HDC hDC) 
 { 
     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; 

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

    if (!lpBits) 
         errhandler("GlobalAlloc", hwnd); 

    // Retrieve the color table (RGBQUAD array) and the bits  
    // (array of palette indices) from the DIB.  
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, 
        DIB_RGB_COLORS)) 
    {
        errhandler("GetDIBits", hwnd); 
    }

    // Create the .BMP file.  
    hf = CreateFile(pszFile, 
                   GENERIC_READ | GENERIC_WRITE, 
                   (DWORD) 0, 
                    NULL, 
                   CREATE_ALWAYS, 
                   FILE_ATTRIBUTE_NORMAL, 
                   (HANDLE) NULL); 
    if (hf == INVALID_HANDLE_VALUE) 
        errhandler("CreateFile", hwnd); 
    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.  
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 
        (LPDWORD) &dwTmp,  NULL)) 
    {
       errhandler("WriteFile", hwnd); 
    }

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

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

    // Close the .BMP file.  
     if (!CloseHandle(hf)) 
           errhandler("CloseHandle", hwnd); 

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

'MFC > Bitmap' 카테고리의 다른 글

핸들변환  (0) 2013.08.16
Bitmap.h  (0) 2013.08.16
Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Posted by 곰돌이짱
,

Bitmap.h

MFC/Bitmap 2013. 8. 16. 11:24

 /*
Bitmap.h
Written by Matthew Fisher

A bitmap class (a 2D array of RGBColor's)
Rather self-explanitory, can only save and load a few primitive formats.
*/


#pragma once

struct BitmapSaveOptions
{
    BitmapSaveOptions()
    {
        //BGREncoding = false;
        //VerticalFlip = false;

        Region = Rectangle2i(Vec2i::Origin, Vec2i::Origin);
        ScratchSpace = NULL;
        ScratchSpaceSize = 0;
        SaveAlpha = false;
        UseBGR = false;
    }
    //bool BGREncoding;
    //bool VerticalFlip;

    Rectangle2i Region;
    BYTE *ScratchSpace;
    UINT ScratchSpaceSize;
    bool SaveAlpha;
    bool UseBGR;
};

class Bitmap
{
public:
    Bitmap();
    Bitmap(const Bitmap &B);
    Bitmap(const Bitmap &B, UINT x, UINT y, UINT Width, UINT Height);
    Bitmap(UINT Width, UINT Height);

    ~Bitmap();

    //
    // Memory
    //
    void FreeMemory();
    void Allocate(UINT Width, UINT Height);
    Bitmap& operator = (const Bitmap &Bmp);

    //
    // Accessors
    //
    __forceinline RGBColor* operator [] (UINT Row) {return &_Data[Row * _Width];}
    __forceinline const RGBColor* operator [] (UINT Row) const {return &_Data[Row * _Width];}
    __forceinline UINT Width() const {return _Width;}
    __forceinline UINT Height() const {return _Height;}
    __forceinline Vec2i Dimensions() const {return Vec2i(_Width, _Height);}
    __forceinline RGBColor SampleNearest(const Vec2f &Pos)
    {
        Vec2i SamplePos(Utility::Bound(Math::Round(Pos.x * (_Width - 1)), 0, int(_Width) - 1),
                        Utility::Bound(Math::Round(Pos.y * (_Height - 1)), 0, int(_Height) - 1));
        return _Data[SamplePos.y * _Width + SamplePos.x];
    }

    //
    // File Functions
    //
    void SaveBMP(const String &Filename) const; //saves bitmap to Filename in 32-bit *.BMP format
    void SavePPM(const String &Filename) const; //saves bitmap to Filename in *.PPM format
    void SavePGM(const String &Filename, int Channel) const;
    void SavePNG(const String &Filename) const; //saves bitmap to Filename in 24-bit *.PNG format
    void SavePNG(const String &Filename, const BitmapSaveOptions &Options) const;
    void SavePNGToMemory(Vector<BYTE> &Buffer) const; //save bitmap to Buffer in *.PNG format
    void SavePNGToMemory(Vector<BYTE> &Buffer, const BitmapSaveOptions &Options) const;
    UINT SaveDelta(const Bitmap &Bmp, const String &Filename) const;
    void LoadBMP(const String &Filename); //loads bitmap from Filename in *.BMP format
    void LoadPNG(const String &Filename); //loads bitmap from Filename in *.PNG format
    void LoadPNGFromMemory(const Vector<BYTE> &Buffer); //loads bitmap from Buffer in *.PNG format
    void LoadSDL(const String &Filename); //loads bitmap from most file formats using SDL
    void LoadDelta(const Bitmap &Bmp, const String &Filename);

#ifdef USE_D3D9
    void LoadFromSurface(LPDIRECT3DSURFACE9 Surface);
    static void SaveSurfaceToPNG(LPDIRECT3DSURFACE9 Surface, const String &Filename, const BitmapSaveOptions &Options);
#endif

    //
    // Transfer Functions
    //
    __forceinline void BltTo(Bitmap &B, const Vec2i &Target) const
    {
        BltTo(B, Target.x, Target.y);
    }
    void BltTo(Bitmap &B, int TargetX, int TargetY) const;
    void BltToNoClipMemcpy(Bitmap &B, UINT TargetX, UINT TargetY) const;
    void BltTo(Bitmap &B, int TargetX, int TargetY, int SourceX, int SourceY, int Width, int Height) const;
   
    enum SamplingType
    {
        SamplingPoint,
        SamplingLinear,
    };
    void StretchBltTo(Bitmap &B, const Rectangle2i &TargetRect, const Rectangle2i &SourceRect, SamplingType Sampling) const;
    void StretchBltTo(Bitmap &B, int TargetX, int TargetY, int TargetWidth, int TargetHeight, int SourceX, int SourceY, int SourceWidth, int SourceHeight, SamplingType Sampling) const;
   
    void LoadGrid(const Grid<float> &Values);
    void LoadGrid(const Grid<float> &Values, float Min, float Max);
    void FlipHorizontal();
    void FlipVertical();
   
    //
    // Query
    //
    UINT Hash32() const;
    UINT64 Hash64() const;
    bool PerfectMatch(const Bitmap &Bmp) const;
    bool Monochrome(RGBColor Color) const;
    bool MonochromeIncludingAlpha(RGBColor Color) const;
    UINT CountPixelsWithColor(RGBColor Color) const;

    //
    // Modifiers
    //
    void ReplaceColor(RGBColor SourceColor, RGBColor NewColor);
    void Clear(const RGBColor &Color);    //clears all pixels to Color
    void Clear();                         //clears all pixels to RGBColor::Black
    void LoadAlphaChannelAsGrayscale();
    void FlipBlueAndRed();

    //
    // Query
    //
    RGBColor AverageColorOverRegion(const Rectangle2f &Region) const;
   
private:
#ifdef USE_PNG
    static void __cdecl PNGReadFromBuffer(png_structp png_ptr, png_bytep data, png_size_t length);
    static void __cdecl PNGWriteToBuffer(png_structp png_ptr, png_bytep data, png_size_t length);
    static void __cdecl PNGFlushBuffer(png_structp png_ptr);
    void PNGCompleteRead(png_structp PngRead, png_infop PngInfo, const String &Filename);
    void PNGCompleteWrite(png_structp PngWrite, png_infop PngInfo, const BitmapSaveOptions &Options) const;
#endif

    UINT _Width, _Height;   //width and height of the bitmap
    RGBColor* _Data;        //Raw RGBColor data in one big array
};

namespace Utility
{
    __forceinline bool PointInsideBitmap(const Bitmap &Bmp, int x, int y)
    {
        return (between(x, 0, int(Bmp.Width()) - 1) &&
                between(y, 0, int(Bmp.Height()) - 1));
    }
}

'MFC > Bitmap' 카테고리의 다른 글

핸들변환  (0) 2013.08.16
Storing an Image  (0) 2013.08.16
Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Posted by 곰돌이짱
,

Bitmap.cpp

MFC/Bitmap 2013. 8. 16. 11:24

 /*
Bitmap.cpp
Written by Matthew Fisher

A bitmap class (a 2D array of RGBColor's)
Rather self-explanitory, can only save and load a few primitive formats.
See Bitmap.h for a complete description
*/


Bitmap::Bitmap()
{
    _Data = 0;
    _Width = 0;
    _Height = 0;
}

Bitmap::Bitmap(UINT Width, UINT Height)
{
    _Data = 0;
    Allocate(Width, Height);
}

Bitmap::~Bitmap()
{
    FreeMemory();
}

Bitmap::Bitmap(const Bitmap &B)
{
    _Data = NULL;
    Allocate(B._Width,B._Height);
    memcpy(_Data,B._Data,sizeof(RGBColor)*_Width*_Height);
}

Bitmap::Bitmap(const Bitmap &B, UINT x, UINT y, UINT Width, UINT Height)
{
    _Data = NULL;
    Allocate(Width, Height);
    Clear();
    for(UINT CurY = 0; CurY < _Height; CurY++)
    {
        for(UINT CurX = 0; CurX < _Width; CurX++)
        {
            _Data[CurY * _Width + CurX] = B[CurY + y][CurX + x];
        }
    }
}

Bitmap& Bitmap::operator = (const Bitmap &B)
{
    Allocate(B._Width,B._Height);
    memcpy(_Data,B._Data,sizeof(RGBColor)*_Width*_Height);
    return *this;
}

void Bitmap::FreeMemory()
{
    if(_Data)
    {
        delete[] _Data;
    }
    _Data = NULL;
    _Width = 0;
    _Height = 0;
}

void Bitmap::Allocate(UINT Width, UINT Height)
{
    if(_Data == NULL || _Width != Width || _Height != Height)
    {
        FreeMemory();
        _Width = Width;
        _Height = Height;
        _Data = new RGBColor[Width * Height];
    }
}

void Bitmap::SaveBMP(const String &Filename) const
{
    BITMAPFILEHEADER    bmfh;  //stores information about the file format
    BITMAPINFOHEADER    bmih;  //stores information about the bitmap
    FILE                *file; //stores file pointer

    //create bitmap file header
    ((unsigned char *)&bmfh.bfType)[0] = 'B';
    ((unsigned char *)&bmfh.bfType)[1] = 'M';
    bmfh.bfSize = 54 + _Height * _Width * 4;
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = 54;

    //create bitmap information header
    bmih.biSize = 40;
    bmih.biWidth = _Width;
    bmih.biHeight = _Height;
    bmih.biPlanes = 1;
    bmih.biBitCount = 32;
    bmih.biCompression = 0;
    bmih.biSizeImage = 0;
    bmih.biXPelsPerMeter = 3800;
    bmih.biYPelsPerMeter = 3800;
    bmih.biClrUsed = 0;
    bmih.biClrImportant = 0;

    //save all header and bitmap information into file
    file = Utility::CheckedFOpen(Filename.CString(), "wb");
    fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, file);
    fwrite(&bmih, sizeof(BITMAPINFOHEADER), 1, file);
    fwrite(_Data, sizeof(RGBColor), _Width * _Height, file);
    fclose(file);
}

void Bitmap::LoadBMP(const String &Filename)
{
    BITMAPFILEHEADER    bmfh;  //stores information about the file format
    BITMAPINFOHEADER    bmih;  //stores information about the bitmap
    FILE                *file; //stores file pointer

    //open the file and read in the headers
    file = Utility::CheckedFOpen(Filename.CString(), "rb");

    fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, file);
    fread(&bmih, sizeof(BITMAPINFOHEADER), 1, file);

    _Width = bmih.biWidth;
    _Height = abs(bmih.biHeight);
    if(bmih.biBitCount == 32)
    {
        //Allocate space for the read operation
        Allocate(_Width, _Height);

        //save all header and bitmap information into file
        fread(_Data, sizeof(RGBColor), _Width * _Height, file);
    }
    else if(bmih.biBitCount == 24)
    {
        //Allocate space for the read operation
        Allocate(_Width, _Height);

        UINT Pitch = _Width * 3;
        UINT ExcessPitch = 0;
        while(double(Pitch / 4) != double(Pitch) / 4.0)
        {
            Pitch++;
            ExcessPitch++;
        }

        unsigned char *DataStore = new unsigned char[Pitch*_Height];
        fread(DataStore, 1, Pitch*_Height, file);

        UINT CurDataPos = 0;
        for(UINT i=0;i<_Height;i++)
        {
            for(UINT i2=0;i2<_Width;i2++)
            {
                RGBColor CurColor;
                CurColor.b = DataStore[CurDataPos++];
                CurColor.g = DataStore[CurDataPos++];
                CurColor.r = DataStore[CurDataPos++];
                CurColor.a = 0;
                _Data[i*_Width+i2] = CurColor;
            }
            CurDataPos += ExcessPitch;
        }

        delete[] DataStore;
    }
    else
    {
        SignalError("Invalid bit count");
    }
    fclose(file);
}

void Bitmap::LoadSDL(const String &Filename)
{
#ifdef USE_SDL
    SDL_Surface *Image = IMG_Load(Filename.CString());
    PersistentAssert(Image != NULL, String("SDL IMG_Load failed on ") + Filename);
   
    //SDL_Surface *FormattedImage = SDL_CreateRGBSurface(SDL_SWSURFACE, Image->w, Image->h, 32, 0, 0, 0, 0);
    SDL_Surface *FormattedImage = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, 0, 0, 0, 0);

    /*SDL_PixelFormat Format;
    Format.palette = NULL;
    Format.BitsPerPixel = 32;
    Format.BytesPerPixel = 4;
    Format.*/


    Utility::Swap(FormattedImage->format->Rmask, FormattedImage->format->Bmask);
   
    SDL_Surface *ConvertedImage = SDL_ConvertSurface(Image, FormattedImage->format, SDL_SWSURFACE);
    PersistentAssert(ConvertedImage != NULL, String("SDL_ConvertSurface failed on ") + Filename);

    Allocate(ConvertedImage->w, ConvertedImage->h);
    //memcpy(_Data, ConvertedImage->pixels, sizeof(RGBColor) * _Width * _Height);
    for(UINT y = 0; y < _Height; y++)
    {
        memcpy(_Data + _Width * y, ((RGBColor *)ConvertedImage->pixels) + _Width * (_Height - 1 - y), sizeof(RGBColor) * _Width);
    }

    SDL_FreeSurface(ConvertedImage);
    SDL_FreeSurface(FormattedImage);
    SDL_FreeSurface(Image);
#else
    PersistentSignalError("LoadSDL called without USE_SDL");
#endif
}

#ifdef USE_PNG
struct PNGDirectMemoryIORead
{
    const Vector<BYTE> *Buffer;
    UINT Offset;
};

void Bitmap::PNGReadFromBuffer(png_structp png_ptr, png_bytep data, png_size_t length)
{
    PNGDirectMemoryIORead *ReadInfo = (PNGDirectMemoryIORead *)png_get_io_ptr(png_ptr);
    memcpy(data, ReadInfo->Buffer->CArray() + ReadInfo->Offset, length);
    ReadInfo->Offset += length;
}

struct PNGDirectMemoryIOWrite
{
    Vector<BYTE> *Buffer;
};

void Bitmap::PNGWriteToBuffer(png_structp png_ptr, png_bytep data, png_size_t length)
{
    PNGDirectMemoryIOWrite *WriteInfo = (PNGDirectMemoryIOWrite *)png_get_io_ptr(png_ptr);
    UINT StartLength = WriteInfo->Buffer->Length();
    WriteInfo->Buffer->ReSize(StartLength + length);
    memcpy(WriteInfo->Buffer->CArray() + StartLength, data, length);
}

void Bitmap::PNGFlushBuffer(png_structp png_ptr)
{
   
}
#endif

void Bitmap::LoadPNG(const String &Filename)
{
#ifdef USE_PNG
    FILE *File;
    File = fopen(Filename.CString(), "rb");
    PersistentAssert(File != NULL, String("File open for LoadPNG failed: ") + String(Filename));

    png_structp PngRead = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    PersistentAssert(PngRead != NULL, "png_create_read_struct failed.");

    png_infop PngInfo = png_create_info_struct(PngRead);
    PersistentAssert(PngInfo != NULL, "png_create_info_struct failed.");

    png_init_io(PngRead, File);
    PNGCompleteRead(PngRead, PngInfo, Filename);

    fclose(File);
#else
    SignalError("LoadPNG called without USE_PNG");
#endif
}

#ifdef USE_PNG
void Bitmap::LoadPNGFromMemory(const Vector<BYTE> &Buffer)
{
    png_structp PngRead = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    Assert(PngRead != NULL, "png_create_read_struct failed.");

    png_infop PngInfo = png_create_info_struct(PngRead);
    Assert(PngInfo != NULL, "png_create_info_struct failed.");

    PNGDirectMemoryIORead ReadInfo;
    ReadInfo.Buffer = &Buffer;
    ReadInfo.Offset = 0;

    png_set_read_fn(PngRead, (void *)&ReadInfo, Bitmap::PNGReadFromBuffer);
    PNGCompleteRead(PngRead, PngInfo, "Memory");
}

void Bitmap::PNGCompleteRead(png_structp PngRead, png_infop PngInfo, const String &Filename)
{
    png_read_png(PngRead, PngInfo, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);
    png_bytepp RowPointers = png_get_rows(PngRead, PngInfo);
    Assert(RowPointers != NULL, "png_get_rows failed.");

    Allocate(PngRead->width, PngRead->height);
    if(PngRead->channels == 3 && PngRead->pixel_depth == 24)
    {
        for(UINT y = 0; y < _Height; y++)
        {
            png_bytep CurRow = RowPointers[_Height - 1 - y];
            for(UINT x = 0; x < _Width; x++)
            {
                (*this)[y][x].r = CurRow[x * 3 + 0];
                (*this)[y][x].g = CurRow[x * 3 + 1];
                (*this)[y][x].b = CurRow[x * 3 + 2];
                (*this)[y][x].a = 0;
            }
        }
    }
    else if(PngRead->channels == 4 && PngRead->pixel_depth == 32)
    {
        for(UINT y = 0; y < _Height; y++)
        {
            png_bytep CurRow = RowPointers[_Height - 1 - y];
            for(UINT x = 0; x < _Width; x++)
            {
                (*this)[y][x].r = CurRow[x * 4 + 0];
                (*this)[y][x].g = CurRow[x * 4 + 1];
                (*this)[y][x].b = CurRow[x * 4 + 2];
                (*this)[y][x].a = CurRow[x * 4 + 3];
            }
        }
    }
    else if(PngRead->channels == 1 && PngRead->pixel_depth == 8)
    {
        for(UINT y = 0; y < _Height; y++)
        {
            png_bytep CurRow = RowPointers[_Height - 1 - y];
            for(UINT x = 0; x < _Width; x++)
            {
                BYTE C = CurRow[x];
                (*this)[y][x] = RGBColor(C, C, C, 0);
            }
        }
    }
    else
    {
        /*PersistentAssert(NULL, String("Unsupported channel # / pixel depth in ") + Filename + String("; ") +
                                      String(PngRead->channels) + String(" channels ") + String(PngRead->pixel_depth) +
                                      String(" bits per pixel"));*/

        Console::WriteLine(String("Unsupported channel # / pixel depth in ") + Filename + String("; ") +
                                      String(PngRead->channels) + String(" channels ") + String(PngRead->pixel_depth) +
                                      String(" bits per pixel"));
        Clear(RGBColor::Magenta);
    }

    png_destroy_read_struct(&PngRead, &PngInfo, NULL);
}
#endif

void Bitmap::SavePNG(const String &Filename) const
{
#ifdef USE_PNG
    BitmapSaveOptions Options;
    SavePNG(Filename, Options);
#else
    SignalError("SavePNG called without USE_PNG");
#endif
}

#ifdef USE_PNG
void Bitmap::SavePNG(const String &Filename, const BitmapSaveOptions &Options) const
{
    PersistentAssert(_Width > 0 && _Height > 0, "Saving empty image");

    FILE *File;
    File = fopen(Filename.CString(), "wb");
    PersistentAssert(File != NULL, String("File open for SavePNG failed: ") + Filename);

    png_structp PngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    PersistentAssert(PngWrite != NULL, "png_create_write_struct failed.");

    png_infop PngInfo = png_create_info_struct(PngWrite);
    PersistentAssert(PngInfo != NULL, "png_create_info_struct failed.");

    png_init_io(PngWrite, File);

    PNGCompleteWrite(PngWrite, PngInfo, Options);

    fclose(File);
}

void Bitmap::SavePNGToMemory(Vector<BYTE> &Buffer) const
{
    BitmapSaveOptions Options;
    SavePNGToMemory(Buffer, Options);
}

void Bitmap::SavePNGToMemory(Vector<BYTE> &Buffer, const BitmapSaveOptions &Options) const
{
    Buffer.FreeMemory();
    png_structp PngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    Assert(PngWrite != NULL, "png_create_write_struct failed");

    png_infop PngInfo = png_create_info_struct(PngWrite);
    Assert(PngInfo != NULL, "png_create_info_struct failed");

    PNGDirectMemoryIORead WriteInfo;
    WriteInfo.Buffer = &Buffer;

    png_set_write_fn(PngWrite, (void *)&WriteInfo, Bitmap::PNGWriteToBuffer, Bitmap::PNGFlushBuffer);
    PNGCompleteWrite(PngWrite, PngInfo, Options);
}

void Bitmap::PNGCompleteWrite(png_structp PngWrite, png_infop PngInfo, const BitmapSaveOptions &Options) const
{
    UINT LocalWidth = _Width;
    UINT LocalHeight = _Height;
    if(Options.Region.Max != Vec2i::Origin)
    {
        LocalWidth = Options.Region.Dimensions().x;
        LocalHeight = Options.Region.Dimensions().y;
    }

    if(Options.SaveAlpha)
    {
        png_set_IHDR(PngWrite, PngInfo, LocalWidth, LocalHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    }
    else
    {
        png_set_IHDR(PngWrite, PngInfo, LocalWidth, LocalHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    }
    png_set_PLTE(PngWrite, PngInfo, NULL, 0);
    png_set_gAMA(PngWrite, PngInfo, 0.0);
    //png_set_sRGB_gAMA_and_cHRM(PngWrite, PngInfo, PNG_sRGB_INTENT_PERCEPTUAL);
   
    png_color_8 ColorInfo;

    ColorInfo.alpha = 0;
    UINT BytesPerPixel = 3;
    if(Options.SaveAlpha)
    {
        ColorInfo.alpha = 8;
        BytesPerPixel = 4;
    }
    ColorInfo.red = 8;
    ColorInfo.green = 8;
    ColorInfo.blue = 8;
    ColorInfo.gray = 0;
    png_set_sBIT(PngWrite, PngInfo, &ColorInfo);
   
   
    UINT ScratchSizeNeeded = (sizeof(png_bytep) + sizeof(png_byte) * BytesPerPixel * LocalWidth) * LocalHeight;
    BYTE *ScratchSpace = Options.ScratchSpace;
    BYTE *ScratchSpaceStart = NULL;
    if(Options.ScratchSpaceSize < ScratchSizeNeeded)
    {
        ScratchSpace = new BYTE[ScratchSizeNeeded];
        ScratchSpaceStart = ScratchSpace;
    }

    png_bytep *RowPointers = (png_bytep *)ScratchSpace;
    ScratchSpace += sizeof(png_bytep) * LocalHeight;
    for(UINT y = 0; y < LocalHeight; y++)
    {
        BYTE *DestRowStart = ScratchSpace;
        ScratchSpace += sizeof(png_byte) * BytesPerPixel * LocalWidth;
        RowPointers[LocalHeight - 1 - y] = DestRowStart;
       
        const RGBColor *SrcRowStart = (*this)[y + Options.Region.Min.y];
        UINT DestRowStartOffset = 0;
       
        if(Options.UseBGR)
        {
            if(Options.SaveAlpha)
            {
                for(UINT x = 0; x < LocalWidth; x++)
                {
                    RGBColor Color = SrcRowStart[x + Options.Region.Min.x];
                    DestRowStart[DestRowStartOffset++] = Color.b;
                    DestRowStart[DestRowStartOffset++] = Color.g;
                    DestRowStart[DestRowStartOffset++] = Color.r;
                    DestRowStart[DestRowStartOffset++] = Color.a;
                }
            }
            else
            {
                for(UINT x = 0; x < LocalWidth; x++)
                {
                    RGBColor Color = SrcRowStart[x + Options.Region.Min.x];
                    DestRowStart[DestRowStartOffset++] = Color.b;
                    DestRowStart[DestRowStartOffset++] = Color.g;
                    DestRowStart[DestRowStartOffset++] = Color.r;
                }
            }
        }
        else
        {
            if(Options.SaveAlpha)
            {
                for(UINT x = 0; x < LocalWidth; x++)
                {
                    RGBColor Color = SrcRowStart[x + Options.Region.Min.x];
                    DestRowStart[DestRowStartOffset++] = Color.r;
                    DestRowStart[DestRowStartOffset++] = Color.g;
                    DestRowStart[DestRowStartOffset++] = Color.b;
                    DestRowStart[DestRowStartOffset++] = Color.a;
                }
            }
            else
            {
                for(UINT x = 0; x < LocalWidth; x++)
                {
                    RGBColor Color = SrcRowStart[x + Options.Region.Min.x];
                    DestRowStart[DestRowStartOffset++] = Color.r;
                    DestRowStart[DestRowStartOffset++] = Color.g;
                    DestRowStart[DestRowStartOffset++] = Color.b;
                }
            }
        }
    }

    png_set_rows(PngWrite, PngInfo, RowPointers);
    png_write_png(PngWrite, PngInfo, NULL, NULL);

    png_destroy_write_struct(&PngWrite, &PngInfo);

    if(ScratchSpaceStart != NULL)
    {
        delete[] ScratchSpaceStart;
    }
}
#endif

void Bitmap::SavePPM(const String &Filename) const
{
    //PPM is a very simple ASCII format
    String FilenameCopy = Filename;
    ofstream file(FilenameCopy.CString());
    file << "P3" << endl;
    file << "# PPM saved to " << FilenameCopy.CString() << endl;
    file << _Width << ' ' << _Height << endl;
    file << 255 << endl;    //maximum value of a component

    for(UINT i2=0;i2<_Height;i2++)
    {
        for(UINT i=0;i<_Width;i++)
        {
            file << int((*this)[i2][i].r) << ' ' << int((*this)[i2][i].g) << ' ' << int((*this)[i2][i].b) << endl;
        }
    }
}

void Bitmap::SavePGM(const String &Filename, int Channel) const
{
    FILE *File;
    File = fopen(Filename.CString(), "wb");
    PersistentAssert(File != NULL, "File open for SavePNG failed.");

    fprintf(File, "P5\n%d %d\n255\n", _Width, _Height);

    for (UINT y = 0; y < _Height; y++)
    {
        for (UINT x = 0; x < _Width; x++)
        {
            unsigned char Value;
            RGBColor Color = (*this)[y][x];
            switch(Channel)
            {
            case 0:
                Value = Color.r;
                break;
            case 1:
                Value = Color.g;
                break;
            case 2:
                Value = Color.b;
                break;
            case 3:
                Value = Color.a;
                break;
            case 4:
            default:
                Value = Utility::BoundToByte((int(Color.r) + int(Color.g) + int(Color.b)) / 3);
            }
            fputc(Value, File);
        }
    }
}

void Bitmap::LoadAlphaChannelAsGrayscale()
{
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            RGBColor &C = (*this)[y][x];
            C.r = C.a;
            C.g = C.a;
            C.b = C.a;
        }
    }
}

void Bitmap::FlipBlueAndRed()
{
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            RGBColor &C = (*this)[y][x];
            unsigned char Temp = C.r;
            C.r = C.b;
            C.b = Temp;
        }
    }
}

void Bitmap::Clear()
{
    memset(_Data, 0, sizeof(RGBColor) * _Width * _Height);
}

void Bitmap::Clear(const RGBColor &Color)
{
    for(UINT i=0;i<_Width;i++)
    {
        _Data[i] = Color;
    }

    for(UINT i2=1;i2<_Height;i2++)
    {
        memcpy(&_Data[i2*_Width], &_Data[0], sizeof(RGBColor) * _Width);
    }
}

void Bitmap::BltTo(Bitmap &B, int TargetX, int TargetY) const
{
    BltTo(B, TargetX, TargetY, 0, 0, _Width, _Height);
}

void Bitmap::BltToNoClipMemcpy(Bitmap &B, UINT TargetX, UINT TargetY) const
{
    const UINT Height = _Height;
    const UINT Width = _Width;
    for(UINT y = 0; y < Height; y++)
    {
        const UINT CurTargetY = y + TargetY;
        memcpy(B._Data + (CurTargetY * B._Width + TargetX), _Data + y * _Width, sizeof(RGBColor) * Width);
    }
}

void Bitmap::BltTo(Bitmap &B, int TargetX, int TargetY, int SourceX, int SourceY, int Width, int Height) const
{
    const int BHeight = B._Height;
    const int BWidth = B._Width;
    for(int y = 0; y < Height; y++)
    {
        const int CurTargetY = y + TargetY;
        const int CurSourceY = y + SourceY;
        if(CurTargetY >= 0 && CurTargetY < BHeight &&
           CurSourceY >= 0 && CurSourceY < int(_Height))
        {
            for(int x = 0; x < Width; x++)
            {
                const int CurTargetX = x + TargetX;
                const int CurSourceX = x + SourceX;
                if(CurTargetX >= 0 && CurTargetX < BWidth &&
                   CurSourceX >= 0 && CurSourceX < int(_Width))
                {
                    B[CurTargetY][CurTargetX] = (*this)[CurSourceY][CurSourceX];
                }
            }
        }
    }
}

void Bitmap::StretchBltTo(Bitmap &B, const Rectangle2i &TargetRect, const Rectangle2i &SourceRect, SamplingType Sampling) const
{
    StretchBltTo(B,
        TargetRect.Min.x, TargetRect.Min.y, TargetRect.Width(), TargetRect.Height(),
        SourceRect.Min.x, SourceRect.Min.y, SourceRect.Width(), SourceRect.Height(), Sampling);
}

void Bitmap::StretchBltTo(Bitmap &B, int TargetX, int TargetY, int TargetWidth, int TargetHeight, int SourceX, int SourceY, int SourceWidth, int SourceHeight, SamplingType Sampling) const
{
    if(Sampling == SamplingPoint)
    {
        const float RatioX = float(SourceWidth) / float(TargetWidth);
        const float RatioY = float(SourceHeight) / float(TargetHeight);
        const float SourceXOffset = float(SourceX + 0.5f * RatioX) + 0.5f;
        const float SourceYOffset = float(SourceY + 0.5f * RatioY) + 0.5f;
        const int Width = _Width;
        const int Height = _Height;
        for(int y = 0; y < TargetHeight; y++)
        {
            for(int x = 0; x < TargetWidth; x++)
            {
                int XMiddle = int(x * RatioX + SourceXOffset);
                int YMiddle = int(y * RatioY + SourceYOffset);
                if(XMiddle >= 0 && XMiddle < Width && YMiddle >= 0 && YMiddle < Height)
                {
                    B._Data[(y + TargetY) * B._Width + x + TargetX] = _Data[YMiddle * _Width + XMiddle];
                }
            }
        }
    }
    else if(Sampling == SamplingLinear)
    {
        for(int y = 0; y < TargetHeight; y++)
        {
            for(int x = 0; x < TargetWidth; x++)
            {
                float XStart = Math::LinearMap(0.0f, float(TargetWidth),  float(SourceX), float(SourceX + SourceWidth ), float(x + 0));
                float XEnd =   Math::LinearMap(0.0f, float(TargetWidth),  float(SourceX), float(SourceX + SourceWidth ), float(x + 1));
                float YStart = Math::LinearMap(0.0f, float(TargetHeight), float(SourceY), float(SourceY + SourceHeight), float(y + 0));
                float YEnd =   Math::LinearMap(0.0f, float(TargetHeight), float(SourceY), float(SourceY + SourceHeight), float(y + 1));

                B[y + TargetY][x + TargetX] = AverageColorOverRegion(Rectangle2f(Vec2f(XStart, YStart), Vec2f(XEnd, YEnd)));
            }
        }
    }
}

RGBColor Bitmap::AverageColorOverRegion(const Rectangle2f &Region) const
{
    Vec3f Result = Vec3f::Origin;
    int XStart = Math::Max(Math::Floor(Region.Min.x), 0);
    int YStart = Math::Max(Math::Floor(Region.Min.y), 0);
    int XEnd = Math::Min(Math::Ceiling(Region.Max.x), int(_Width) - 1);
    int YEnd = Math::Min(Math::Ceiling(Region.Max.y), int(_Height) - 1);

    const RGBColor *Data = _Data;
    const UINT Width = _Width;
    UINT Count = 0;
    for(int y = YStart; y <= YEnd; y++)
    {
        for(int x = XStart; x <= XEnd; x++)
        {
            Count++;
            Result += Vec3f(Data[y * Width + x]);
        }
    }
    return RGBColor(Result * (1.0f / float(Count)));
}

void Bitmap::LoadGrid(const Grid<float> &Values)
{
    float Min = Values(0, 0);
    float Max = Values(0, 0);
    for(UINT y = 0; y < Values.Rows(); y++)
    {
        for(UINT x = 0; x < Values.Cols(); x++)
        {
            if(Values(y, x) != 0.0f)
            {
                if(Min == 0.0f)
                {
                    Min = Values(y, x);
                }
                Min = Math::Min(Min, Values(y, x));
            }
            Max = Math::Max(Max, Values(y, x));
        }
    }
    LoadGrid(Values, Min, Max);
}

void Bitmap::LoadGrid(const Grid<float> &Values, float Min, float Max)
{
    Allocate(Values.Cols(), Values.Rows());
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            BYTE Intensity = 0;
            if(Max != Min)
            {
                Intensity = Utility::BoundToByte(Math::LinearMap(Min, Max, 0.0f, 255.0f, Values(y, x)));
            }
            if(Values(y, x) == 0.0f)
            {
                (*this)[y][x] = RGBColor::Magenta;
            }
            else
            {
                (*this)[y][x] = RGBColor(Intensity, Intensity, Intensity);
            }
        }
    }
}

/*BITMAP_HASH Bitmap::UnorientedHash() const
{
    BITMAP_HASH Result = _Width + _Height + _Width * _Height + _Width * _Width * _Height;
    for(UINT y=0;y<_Height;y++)
    {
        for(UINT x=0;x<_Width;x++)
        {
            RGBColor C = (*this)[y][x];
            Result += int(C.r) * 541 +
                      int(C.g) * 978 +
                      int(C.b) * 1024 +
                      int(C.r) * int(C.g);
        }
    }
    return Result;
}*/


void Bitmap::ReplaceColor(RGBColor CurrentColor, RGBColor NewColor)
{
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            if((*this)[y][x] == CurrentColor)
            {
                (*this)[y][x] = NewColor;
            }
        }
    }
}

UINT Bitmap::Hash32() const
{
    return Utility::Hash32((BYTE *)_Data, sizeof(RGBColor) * _Width * _Height) + (_Width * 785 + _Height * 97);
}

UINT64 Bitmap::Hash64() const
{
    return Utility::Hash64((BYTE *)_Data, sizeof(RGBColor) * _Width * _Height) + (_Width * 785 + _Height * 97);
}

UINT Bitmap::CountPixelsWithColor(RGBColor Color) const
{
    UINT Result = 0;
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            if(_Data[y * _Width + x] == Color)
            {
                Result++;
            }
        }
    }
    return Result;
}

bool Bitmap::Monochrome(RGBColor Color) const
{
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            if(_Data[y * _Width + x] != Color)
            {
                return false;
            }
        }
    }
    return true;
}

bool Bitmap::MonochromeIncludingAlpha(RGBColor Color) const
{
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            const RGBColor C = _Data[y * _Width + x];
            if(C.r != Color.r || C.g != Color.g || C.b != Color.b || C.a != Color.a)
            {
                return false;
            }
        }
    }
    return true;
}

bool Bitmap::PerfectMatch(const Bitmap &Bmp) const
{
    if(Bmp.Dimensions() != Dimensions())
    {
        return false;
    }
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            if ( (*this)[y][x].r != Bmp[y][x].r ||
                 (*this)[y][x].g != Bmp[y][x].g ||
                 (*this)[y][x].b != Bmp[y][x].b)
            {
                return false;
            }
        }
    }
    return true;
}

void Bitmap::FlipHorizontal()
{
    Bitmap BTemp = *this;
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            (*this)[y][x] = BTemp[y][_Width - 1 - x];
        }
    }
}

void Bitmap::FlipVertical()
{
    Bitmap BTemp = *this;
    for(UINT y = 0; y < _Height; y++)
    {
        for(UINT x = 0; x < _Width; x++)
        {
            (*this)[y][x] = BTemp[_Height - 1 - y][x];
        }
    }
}

#if 0
//
// The following is taken from
// http://www.suchit-tiwari.org/antialias.html
//
void Bitmap::DrawLine(int X0, int Y0, int X1, int Y1)
{
    const UINT NumLevels = 256;
    const UINT IntensityBits = 8;
    const UINT BaseColor = 0;

    unsigned short IntensityShift, ErrorAdj, ErrorAcc;
    unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
    short DeltaX, DeltaY, Temp, XDir;

    X0 = Utility::Bound(X0, 0, int(_Width) - 1);
    X1 = Utility::Bound(X1, 0, int(_Width) - 1);

    Y0 = Utility::Bound(Y0, 0, int(_Height) - 1);
    Y1 = Utility::Bound(Y1, 0, int(_Height) - 1);

    /* Make sure the line runs top to bottom */
    if (Y0 > Y1)
    {
        Temp = Y0; Y0 = Y1; Y1 = Temp;
        Temp = X0; X0 = X1; X1 = Temp;
    }

    /* Draw the initial pixel, which is always exactly intersected by
      the line and so needs no weighting */

    (*this)[Y0][X0] = RGBColor::Black;

    if ((DeltaX = X1 - X0) >= 0)
    {
      XDir = 1;
    }
    else
    {
      XDir = -1;
      DeltaX = -DeltaX; /* make DeltaX positive */
    }
    /* Special-case horizontal, vertical, and diagonal lines, which
      require no weighting because they go right through the center of
      every pixel */

    if ((DeltaY = Y1 - Y0) == 0)
    {
        /* Horizontal line */
        while (DeltaX-- != 0)
        {
            X0 += XDir;
            (*this)[Y0][X0] = RGBColor::Black;
        }
        return;
    }
    if (DeltaX == 0) {
        /* Vertical line */
        do
        {
            Y0++;
            (*this)[Y0][X0] = RGBColor::Black;
        } while (--DeltaY != 0);
        return;
    }
    if (DeltaX == DeltaY) {
      /* Diagonal line */
      do
      {
         X0 += XDir;
         Y0++;
         (*this)[Y0][X0] = RGBColor::Black;
      } while (--DeltaY != 0);
      return;
    }
    /* Line is not horizontal, diagonal, or vertical */
    ErrorAcc = 0/* initialize the line error accumulator to 0 */
    /* # of bits by which to shift ErrorAcc to get intensity level */
    IntensityShift = 16 - IntensityBits;
    /* Mask used to flip all bits in an intensity weighting, producing the
      result (1 - intensity weighting) */

    WeightingComplementMask = NumLevels - 1;
    /* Is this an X-major or Y-major line? */
    if (DeltaY > DeltaX)
    {
      /* Y-major line; calculate 16-bit fixed-point fractional part of a
         pixel that X advances each time Y advances 1 pixel, truncating the
         result so that we won't overrun the endpoint along the X axis */

      ErrorAdj = unsigned short(((unsigned long) DeltaX << 16) / (unsigned long) DeltaY);
      /* Draw all pixels other than the first and last */
      while (--DeltaY) {
         ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
         ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
         if (ErrorAcc <= ErrorAccTemp) {
            /* The error accumulator turned over, so advance the X coord */
            X0 += XDir;
         }
         Y0++; /* Y-major, so always advance Y */
         /* The IntensityBits most significant bits of ErrorAcc give us the
            intensity weighting for this pixel, and the complement of the
            weighting for the paired pixel */

         Weighting = ErrorAcc >> IntensityShift;
        
         unsigned char LVal = (BaseColor + Weighting);
         (*this)[Y0][X0] = RGBColor(LVal, LVal, LVal);

         LVal = BaseColor + (Weighting ^ WeightingComplementMask);
         (*this)[Y0][X0 + XDir] = RGBColor(LVal, LVal, LVal);
      }
      /* Draw the final pixel, which is always exactly intersected by the line
         and so needs no weighting */

      (*this)[Y1][X1] = RGBColor::Black;
      return;
    }
    /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
      pixel that Y advances each time X advances 1 pixel, truncating the
      result to avoid overrunning the endpoint along the X axis */

    ErrorAdj = unsigned short(((unsigned long) DeltaY << 16) / (unsigned long) DeltaX);
    /* Draw all pixels other than the first and last */
    while (--DeltaX) {
      ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
      ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
      if (ErrorAcc <= ErrorAccTemp) {
         /* The error accumulator turned over, so advance the Y coord */
         Y0++;
      }
      X0 += XDir; /* X-major, so always advance X */
      /* The IntensityBits most significant bits of ErrorAcc give us the
         intensity weighting for this pixel, and the complement of the
         weighting for the paired pixel */

      Weighting = ErrorAcc >> IntensityShift;
     
      unsigned char LVal = (BaseColor + Weighting);
      (*this)[Y0][X0] = RGBColor(LVal, LVal, LVal);

      LVal = BaseColor + (Weighting ^ WeightingComplementMask);
      (*this)[Y0 + 1][X0] = RGBColor(LVal, LVal, LVal);
    }
    /* Draw the final pixel, which is always exactly intersected by the line
      and so needs no weighting */

    (*this)[Y1][X1] = RGBColor::Black;
}
#endif

#ifdef USE_D3D9
void Bitmap::LoadFromSurface(LPDIRECT3DSURFACE9 Surface)
{
    D3DSURFACE_DESC Desc;
    D3DLOCKED_RECT LockedRect;
    D3DAlwaysValidate(Surface->GetDesc(&Desc), "GetDesc");
    PersistentAssert(Desc.Format == D3DFMT_A8R8G8B8 ||
                     Desc.Format == D3DFMT_X8R8G8B8, "Invalid surface format");
    Allocate(Desc.Width, Desc.Height);
    D3DAlwaysValidate(Surface->LockRect(&LockedRect, NULL, 0), "LockRect");
    BYTE *_Data = (BYTE *)LockedRect.pBits;
    if(Desc.Format == D3DFMT_A8R8G8B8 || Desc.Format == D3DFMT_X8R8G8B8)
    {
        for(UINT y = 0; y < _Height; y++)
        {
            RGBColor *RowStart = (RGBColor *)(_Data + y * LockedRect.Pitch);
            memcpy((*this)[_Height - 1 - y], RowStart, sizeof(RGBColor) * _Width);
            //for(UINT x = 0; x < _Width; x++)
            //{
            //    (*this)[y][x] = RowStart[x];
            //}
        }
    }
    D3DAlwaysValidate(Surface->UnlockRect(), "UnlockRect");
}

UINT Bitmap::SaveDelta(const Bitmap &Bmp, const String &Filename) const
{
    const UINT Width = _Width;
    const UINT Height = _Height;
    const UINT PixelCount = Width * Height;
    const RGBColor *MyData = _Data;
    const RGBColor *PrevData = Bmp._Data;
    PersistentAssert(Width == Bmp.Width() && Height == Bmp.Height(), "Invalid dimensions");
   
    static BYTE *Storage = NULL;
    if(Storage == NULL)
    {
        Storage = new BYTE[PixelCount * sizeof(RGBColor) * 2];
    }
    BYTE *CurStorageByte = Storage;

    UINT PixelIndex = 0;
    while(PixelIndex < PixelCount)
    {
        const WORD MyColor16 = RGBColor16FromRGBColor32(*MyData);
        const WORD PrevColor16 = RGBColor16FromRGBColor32(*PrevData);
        if(MyColor16 == PrevColor16)
        {
            BYTE *Counter = CurStorageByte;
            CurStorageByte++;
            *Counter = 255;
            for(UINT MatchIndex = 0; MatchIndex < 128; MatchIndex++)
            {
                const WORD MatchMyColor16 = RGBColor16FromRGBColor32(*(MyData));
                const WORD MatchPrevColor16 = RGBColor16FromRGBColor32(*(PrevData));
                if(MatchMyColor16 == MatchPrevColor16)
                {
                    PrevData++;
                    MyData++;
                    PixelIndex++;
                    (*Counter)++;
                }
                else
                {
                    break;
                }
            }
        }
        else
        {
            BYTE *Counter = CurStorageByte;
            CurStorageByte++;
            *Counter = 127;
            //const UINT ChromaSubsamplingRate = 3;
            //UINT ChromaSubsamplingIndex = ChromaSubsamplingRate - 1;
            for(UINT MatchIndex = 0; MatchIndex < 128; MatchIndex++)
            {
                RGBColor MatchMyColor = *(MyData);
                const WORD MatchMyColor16 = RGBColor16FromRGBColor32(MatchMyColor);
                const WORD MatchPrevColor16 = RGBColor16FromRGBColor32(*(PrevData));
                if(MatchMyColor16 != MatchPrevColor16)
                {
                    //ChromaSubsamplingIndex++;
                    //if(ChromaSubsamplingIndex == ChromaSubsamplingRate)
                    {
                        //ChromaSubsamplingIndex = 0;
                        *((WORD*)CurStorageByte) = RGBColor16FromRGBColor32(MatchMyColor);
                        CurStorageByte += 2;
                    }
                    //else
                    //{
                    //    *CurStorageByte = (int(MatchMyColor.r) + int(MatchMyColor.g) + int(MatchMyColor.b)) / 3;
                    //    CurStorageByte++;
                    //}
                    PrevData++;
                    MyData++;
                    PixelIndex++;
                    (*Counter)++;
                }
                else
                {
                    break;
                }
            }
        }
    }
    FILE *File = Utility::CheckedFOpen(Filename.CString(), "wb");
    fwrite(Storage, CurStorageByte - Storage, 1, File);
    fclose(File);
    return (CurStorageByte - Storage);
}

void Bitmap::LoadDelta(const Bitmap &Bmp, const String &Filename)
{
    *this = Bmp;
    const UINT Width = _Width;
    const UINT Height = _Height;
    const UINT PixelCount = Width * Height;
    RGBColor *MyData = _Data;
    const RGBColor *PrevData = Bmp._Data;
   
    Vector<BYTE> Storage;
    Utility::GetFileData(Filename, Storage);
    BYTE *CurStorageByte = Storage.CArray();
    UINT PixelIndex = 0;
    while(PixelIndex < PixelCount)
    {
        BYTE Counter = *CurStorageByte;
        CurStorageByte++;
        if(Counter >= 0 && Counter < 128)
        {
            PixelIndex += Counter + 1;
        }
        else
        {
            Counter -= 128;
            //const UINT ChromaSubsamplingRate = 3;
            //UINT ChromaSubsamplingIndex = ChromaSubsamplingRate - 1;
            RGBColor PrevColor;
            for(UINT MatchIndex = 0; MatchIndex <= Counter; MatchIndex++)
            {
                //ChromaSubsamplingIndex++;
                //if(ChromaSubsamplingIndex == ChromaSubsamplingRate)
                {
                    //ChromaSubsamplingIndex = 0;
                    PrevColor = RGBColor32FromRGBColor16(*((WORD*)CurStorageByte));
                    CurStorageByte += 2;
                    MyData[PixelIndex] = PrevColor;
                }
                //else
                //{
                //    UINT L = (*CurStorageByte);
                //    CurStorageByte++;
                //    if(PrevColor.r == 0 && PrevColor.g == 0 && PrevColor.b == 0)
                //    {
                //        PrevColor = RGBColor(1, 1, 1);
                //    }
                //    Vec3f D = Vec3f::Normalize(Vec3f(PrevColor));
                //    D *= (3.0f / 255.0f) * L / (D.x + D.y + D.z);
                //    UINT B = (int(RGBColor(D).r) + int(RGBColor(D).g) + int(RGBColor(D).b)) / 3;
                //    MyData[PixelIndex] = RGBColor(D);
                //}
                PixelIndex++;
            }
        }
    }
}

#if 0
void Bitmap::SaveSurfaceToZLIB(LPDIRECT3DSURFACE9 Surface, const String &Filename, const BitmapSaveOptions &Options)
{
    D3DSURFACE_DESC Desc;
    D3DLOCKED_RECT LockedRect;
    D3DAlwaysValidate(Surface->GetDesc(&Desc), "GetDesc");
    PersistentAssert(Desc.Format == D3DFMT_A8R8G8B8 ||
                     Desc.Format == D3DFMT_X8R8G8B8, "Invalid surface format");
    D3DAlwaysValidate(Surface->LockRect(&LockedRect, NULL, 0), "LockRect");
    const UINT Width = Desc.Width;
    const UINT Height = Desc.Height;
    BYTE *_Data = (BYTE *)LockedRect.pBits;

    int Result;
    z_stream Stream;

    const UINT InputBytes = Width * Height * sizeof(RGBColor);
    BYTE *CompressedStream = new BYTE[InputBytes + 1024];

    Stream.zalloc = Z_NULL;
    Stream.zfree = Z_NULL;
    Stream.opaque = Z_NULL;
   
    Stream.avail_in = InputBytes;
    Stream.next_in = _Data;

    Stream.data_type = Z_BINARY;

    Stream.avail_out = InputBytes;
    Stream.next_out = CompressedStream;

    const int Level = 6;
    //Result = deflateInit(&Stream, Level);
    Result = deflateInit2(&Stream, Level, Z_DEFLATED, 8, 8, Z_HUFFMAN_ONLY);
    PersistentAssert(Result == Z_OK, "deflateInit failed");

    Result = deflate(&Stream, Z_FINISH);
    PersistentAssert(Result == Z_STREAM_END, "deflate failed");

    deflateEnd(&Stream);

    delete[] CompressedStream;

    D3DAlwaysValidate(Surface->UnlockRect(), "UnlockRect");
    //fclose(File);
}
#endif

#ifdef USE_PNG
void Bitmap::SaveSurfaceToPNG(LPDIRECT3DSURFACE9 Surface, const String &Filename, const BitmapSaveOptions &Options)
{
    D3DSURFACE_DESC Desc;
    D3DLOCKED_RECT LockedRect;
    D3DAlwaysValidate(Surface->GetDesc(&Desc), "GetDesc");
    PersistentAssert(Desc.Format == D3DFMT_A8R8G8B8 ||
                     Desc.Format == D3DFMT_X8R8G8B8, "Invalid surface format");
    D3DAlwaysValidate(Surface->LockRect(&LockedRect, NULL, 0), "LockRect");
    const UINT Width = Desc.Width;
    const UINT Height = Desc.Height;
    BYTE *_Data = (BYTE *)LockedRect.pBits;
    /*for(UINT y = 0; y < Height; y++)
    {
        RGBColor *RowStart = (RGBColor *)(_Data + y * LockedRect.Pitch);
        memcpy((*this)[Height - 1 - y], RowStart, sizeof(RGBColor) * Width);
        //for(UINT x = 0; x < _Width; x++)
        //{
        //    (*this)[y][x] = RowStart[x];
        //}
    }*/


    FILE *File;
    File = fopen(Filename.CString(), "wb");
    PersistentAssert(File != NULL, "File open for SavePNG failed");

    png_structp PngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    PersistentAssert(PngWrite != NULL, "png_create_write_struct failed");

    png_infop PngInfo = png_create_info_struct(PngWrite);
    PersistentAssert(PngInfo != NULL, "png_create_info_struct failed");

    png_init_io(PngWrite, File);

    png_set_IHDR(PngWrite, PngInfo, Width, Height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   
    png_set_PLTE(PngWrite, PngInfo, NULL, 0);
    png_set_gAMA(PngWrite, PngInfo, 0.0);
   
    png_color_8 ColorInfo;

    ColorInfo.alpha = 0;
    UINT BytesPerPixel = 3;
    if(Options.SaveAlpha)
    {
        ColorInfo.alpha = 8;
        BytesPerPixel = 4;
    }
    ColorInfo.red = 8;
    ColorInfo.green = 8;
    ColorInfo.blue = 8;
    ColorInfo.gray = 0;
    png_set_sBIT(PngWrite, PngInfo, &ColorInfo);
   
   
    UINT ScratchSizeNeeded = sizeof(png_bytep) * Height;
    BYTE *ScratchSpace = Options.ScratchSpace;
    BYTE *ScratchSpaceStart = NULL;
    if(Options.ScratchSpaceSize < ScratchSizeNeeded)
    {
        ScratchSpace = new BYTE[ScratchSizeNeeded];
        ScratchSpaceStart = ScratchSpace;
    }

    png_bytep *RowPointers = (png_bytep *)ScratchSpace;
    for(UINT y = 0; y < Height; y++)
    {
        RowPointers[y] = (_Data + y * LockedRect.Pitch);
    }

    png_set_rows(PngWrite, PngInfo, RowPointers);
    png_write_png(PngWrite, PngInfo, NULL, NULL);

    png_destroy_write_struct(&PngWrite, &PngInfo);

    if(ScratchSpaceStart != NULL)
    {
        delete[] ScratchSpaceStart;
    }

    D3DAlwaysValidate(Surface->UnlockRect(), "UnlockRect");
    fclose(File);
}
#endif

#endif

Bitmap operator + (const Bitmap &L, const Bitmap &R)
{
    Assert(L.Width() == R.Width() && L.Height() == R.Height(), "Invalid dimensions in Bitmap operator +");
    Bitmap Result = L;
    for(UINT y = 0; y < Result.Height(); y++)
    {
        for(UINT x = 0; x < Result.Width(); x++)
        {
            Result[y][x] += R[y][x];
        }
    }
    return Result;
}

'MFC > Bitmap' 카테고리의 다른 글

Storing an Image  (0) 2013.08.16
Bitmap.h  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Converting DDB to DIB  (0) 2013.08.08
Posted by 곰돌이짱
,

 BITMAP  bm;
 CBitmap  Bitmap;
 CDC   MemDC, *pDC;
 
 pDC = this->GetDC();
 
 Bitmap.LoadBitmap(IDB_BMP_IMG);
   
 MemDC.CreateCompatibleDC(pDC);
   
 MemDC.SelectObject(&Bitmap);
   
 Bitmap.GetObject(sizeof(bm), &bm);

 

pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &MemDC, 0, 0, SRCCOPY);

'MFC > Bitmap' 카테고리의 다른 글

Bitmap.h  (0) 2013.08.16
Bitmap.cpp  (0) 2013.08.16
Writing a window image to a BMP file  (0) 2013.08.08
Converting DDB to DIB  (0) 2013.08.08
memory dc to bitmap file  (0) 2013.08.08
Posted by 곰돌이짱
,
  1. BOOL WriteWindowToDIB( LPTSTR szFile, CWnd *pWnd )
  2. {
  3. CBitmap bitmap;
  4. CWindowDC dc(pWnd);
  5. CDC memDC;
  6. CRect rect;
  7.  
  8. memDC.CreateCompatibleDC(&dc);
  9.  
  10. pWnd->GetWindowRect(rect);
  11.  
  12. bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height() );
  13. CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
  14. memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);
  15.  
  16. // Create logical palette if device support a palette
  17. CPalette pal;
  18. if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
  19. {
  20. UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
  21. LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
  22. pLP->palVersion = 0x300;
  23.  
  24. pLP->palNumEntries =
  25. GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry );
  26.  
  27. // Create the palette
  28. pal.CreatePalette( pLP );
  29.  
  30. delete[] pLP;
  31. }
  32.  
  33. memDC.SelectObject(pOldBitmap);
  34.  
  35. // Convert the bitmap to a DIB
  36. HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, &pal );
  37.  
  38. if( hDIB == NULL )
  39. return FALSE;
  40.  
  41. // Write it to file
  42. WriteDIB( szFile, hDIB );
  43.  
  44. // Free the memory allocated by DDBToDIB for the DIB
  45. GlobalFree( hDIB );
  46. return TRUE;
  47. }

'MFC > Bitmap' 카테고리의 다른 글

Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Converting DDB to DIB  (0) 2013.08.08
memory dc to bitmap file  (0) 2013.08.08
Bitmap Save  (0) 2013.08.08
Posted by 곰돌이짱
,

Converting DDB to DIB

MFC/Bitmap 2013. 8. 8. 17:55

A device-dependent bitmap (DDB) is structured in such a way that it matches very closely the form in which the bitmap is finally displayed by the device driver. For this reason the DDB is unlikely to be compatible with other display devices. A device-independent bitmap (DIB) on the other hand has a logical layout and can be decifered by any device driver. The disadvantage with DIB though is that it is much slower to render onto the device as compared to a DDB.

One situation where we need to convert a DDB to a DIB is when we want to save the bitmap to a file. The BMP files are infact just composed of a short header followed by information in a DIB.

The steps involved in creating the DIB are:

  1. Initialize a BITMAPINFOHEADER data structure. We use information in the bitmap to determine the widht, height and the bit count. The compression field is set based on the argument passed into the function. It's best to use the BI_RGB compression for greater portability and faster rendering.
  2. Select and realize the logical palette associated with the bitmap. This is passed in as the last argument to the function. If a palette is not provided use the default palette.
  3. Determine the number of bytes required for the bitmap bits. First allocate enough memory for BITMAPINFOHEADER and the color table and then call GetDIBits() to size. Supplying a NULL for the lpBits parameter instructs GetDIBits() to biSizeImage field in the bitmapinfoheader. Sometimes, this does not work (depending on the device driver) in which case we make our own estimate. We can compute this since we already know the width, height, the number of bits per pixel and the fact that each row of pixels will occupy a multiple of 4 bytes (32 bits).
  4. Given the final size of the bitmap bits, reallocate the memory block to hold the bitmapinfoheader, the color table and the bitmap bits.
  5. Finally call the GetDIBits() again to get the bitmap bits.
  1. // DDBToDIB - Creates a DIB from a DDB
  2. // bitmap - Device dependent bitmap
  3. // dwCompression - Type of compression - see BITMAPINFOHEADER
  4. // pPal - Logical palette
  5. HANDLE DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal )
  6. {
  7. BITMAP bm;
  8. BITMAPINFOHEADER bi;
  9. LPBITMAPINFOHEADER lpbi;
  10. DWORD dwLen;
  11. HANDLE hDIB;
  12. HANDLE handle;
  13. HDC hDC;
  14. HPALETTE hPal;
  15.  
  16.  
  17. ASSERT( bitmap.GetSafeHandle() );
  18.  
  19. // The function has no arg for bitfields
  20. if( dwCompression == BI_BITFIELDS )
  21. return NULL;
  22.  
  23. // If a palette has not been supplied use defaul palette
  24. hPal = (HPALETTE) pPal->GetSafeHandle();
  25. if (hPal==NULL)
  26. hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
  27.  
  28. // Get bitmap information
  29. bitmap.GetObject(sizeof(bm),(LPSTR)&bm);
  30.  
  31. // Initialize the bitmapinfoheader
  32. bi.biSize = sizeof(BITMAPINFOHEADER);
  33. bi.biWidth = bm.bmWidth;
  34. bi.biHeight = bm.bmHeight;
  35. bi.biPlanes = 1;
  36. bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
  37. bi.biCompression = dwCompression;
  38. bi.biSizeImage = 0;
  39. bi.biXPelsPerMeter = 0;
  40. bi.biYPelsPerMeter = 0;
  41. bi.biClrUsed = 0;
  42. bi.biClrImportant = 0;
  43.  
  44. // Compute the size of the infoheader and the color table
  45. int nColors = (1 << bi.biBitCount);
  46. if( nColors > 256 )
  47. nColors = 0;
  48. dwLen = bi.biSize + nColors * sizeof(RGBQUAD);
  49.  
  50. // We need a device context to get the DIB from
  51. hDC = GetDC(NULL);
  52. hPal = SelectPalette(hDC,hPal,FALSE);
  53. RealizePalette(hDC);
  54.  
  55. // Allocate enough memory to hold bitmapinfoheader and color table
  56. hDIB = GlobalAlloc(GMEM_FIXED,dwLen);
  57.  
  58. if (!hDIB){
  59. SelectPalette(hDC,hPal,FALSE);
  60. ReleaseDC(NULL,hDC);
  61. return NULL;
  62. }
  63.  
  64. lpbi = (LPBITMAPINFOHEADER)hDIB;
  65.  
  66. *lpbi = bi;
  67.  
  68. // Call GetDIBits with a NULL lpBits param, so the device driver
  69. // will calculate the biSizeImage field
  70. GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight,
  71. (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);
  72.  
  73. bi = *lpbi;
  74.  
  75. // If the driver did not fill in the biSizeImage field, then compute it
  76. // Each scan line of the image is aligned on a DWORD (32bit) boundary
  77. if (bi.biSizeImage == 0){
  78. bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
  79. * bi.biHeight;
  80.  
  81. // If a compression scheme is used the result may infact be larger
  82. // Increase the size to account for this.
  83. if (dwCompression != BI_RGB)
  84. bi.biSizeImage = (bi.biSizeImage * 3) / 2;
  85. }
  86.  
  87. // Realloc the buffer so that it can hold all the bits
  88. dwLen += bi.biSizeImage;
  89. if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
  90. hDIB = handle;
  91. else{
  92. GlobalFree(hDIB);
  93.  
  94. // Reselect the original palette
  95. SelectPalette(hDC,hPal,FALSE);
  96. ReleaseDC(NULL,hDC);
  97. return NULL;
  98. }
  99.  
  100. // Get the bitmap bits
  101. lpbi = (LPBITMAPINFOHEADER)hDIB;
  102.  
  103. // FINALLY get the DIB
  104. BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
  105. 0L, // Start scan line
  106. (DWORD)bi.biHeight, // # of scan lines
  107. (LPBYTE)lpbi // address for bitmap bits
  108. + (bi.biSize + nColors * sizeof(RGBQUAD)),
  109. (LPBITMAPINFO)lpbi, // address of bitmapinfo
  110. (DWORD)DIB_RGB_COLORS); // Use RGB for color table
  111.  
  112. if( !bGotBits )
  113. {
  114. GlobalFree(hDIB);
  115. SelectPalette(hDC,hPal,FALSE);
  116. ReleaseDC(NULL,hDC);
  117. return NULL;
  118. }
  119.  
  120. SelectPalette(hDC,hPal,FALSE);
  121. ReleaseDC(NULL,hDC);
  122. return hDIB;
  123. }

 


'MFC > Bitmap' 카테고리의 다른 글

Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
memory dc to bitmap file  (0) 2013.08.08
Bitmap Save  (0) 2013.08.08
Posted by 곰돌이짱
,
SaveMemDCToBitmapNoPalete(HDC p_hMemDC,HBITMAP p_hBitmap)
{
 HDC hMemDC = p_hMemDC;
 HBITMAP hBitmap = p_hBitmap;
 int   wBitCount = 32;
 
 BITMAP   Bitmap;  
 BITMAPFILEHEADER   bmfHdr;    
 BITMAPINFOHEADER   bi;
 
 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 
 
 bi.biSize = sizeof(BITMAPINFOHEADER);    
 bi.biWidth = Bitmap.bmWidth;    
 bi.biHeight = Bitmap.bmHeight;  
 bi.biPlanes = 1;    
 bi.biBitCount = wBitCount;    
 bi.biCompression = BI_RGB;    
 bi.biSizeImage = 0;  
 bi.biXPelsPerMeter = 0;    
 bi.biYPelsPerMeter = 0;    
 bi.biClrUsed = 0;    
 bi.biClrImportant = 0; 
 
 DWORD dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight; 
 
 HANDLE hDib = GlobalAlloc(GHND,dwBmBitsSize+sizeof(BITMAPINFOHEADER)); 
 LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);    
 *lpbi = bi;
 
 GetDIBits(hMemDC, hBitmap, 0, (UINT)Bitmap.bmHeight,  
  (LPSTR)lpbi + sizeof(BITMAPINFOHEADER), (BITMAPINFO *)lpbi, DIB_RGB_COLORS);    
 
 HANDLE fh = CreateFile("c:\\temp.bmp",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
  FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);   
 ASSERT(fh != INVALID_HANDLE_VALUE);
 
 DWORD dwDIBSize   =   sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmBitsSize;
 
 bmfHdr.bfType = 0x4D42;    
 bmfHdr.bfSize = dwDIBSize;  
 bmfHdr.bfReserved1 = 0;    
 bmfHdr.bfReserved2 = 0;    
 bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);    
 
 DWORD dwWritten;
 
 WriteFile(fh,   (LPSTR)&bmfHdr,   sizeof(BITMAPFILEHEADER),   &dwWritten,   NULL);    
 WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);    
 GlobalUnlock(hDib);    
 GlobalFree(hDib);    
 CloseHandle(fh);
 return TRUE;
}

'MFC > Bitmap' 카테고리의 다른 글

Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Converting DDB to DIB  (0) 2013.08.08
Bitmap Save  (0) 2013.08.08
Posted by 곰돌이짱
,

Bitmap Save

MFC/Bitmap 2013. 8. 8. 17:50
void CCatchScreenDlg::SaveScreenToFile(LPCTSTR szFileName)
{
	HDC hScrDC = ::GetDC(NULL);
	HDC hMemDC = NULL;

	BYTE *lpBitmapBits = NULL; 

	int nWidth = GetSystemMetrics(SM_CXSCREEN);
	int nHeight = GetSystemMetrics(SM_CYSCREEN); 

	hMemDC = ::CreateCompatibleDC(hScrDC); 

	BITMAPINFO bi; 
	ZeroMemory(&bi, sizeof(BITMAPINFO));
	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bi.bmiHeader.biWidth = nWidth;
	bi.bmiHeader.biHeight = nHeight;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 24;

	HBITMAP bitmap = ::CreateDIBSection(hMemDC, &bi, DIB_RGB_COLORS, (LPVOID*)&lpBitmapBits, NULL, 0);
	HGDIOBJ oldbmp = ::SelectObject(hMemDC, bitmap); 

	::BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, 0, 0, SRCCOPY);

	BITMAPFILEHEADER bh;
	ZeroMemory(&bh, sizeof(BITMAPFILEHEADER));
	bh.bfType = 0x4d42; //bitmap 
	bh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bh.bfSize = bh.bfOffBits + ((nWidth*nHeight)*3);

	CFile file;
	if(file.Open(szFileName, CFile::modeCreate | CFile::modeWrite))
	{ 
		file.Write(&bh, sizeof(BITMAPFILEHEADER));
		file.Write(&(bi.bmiHeader), sizeof(BITMAPINFOHEADER));
		file.Write(lpBitmapBits, 3 * nWidth * nHeight);
		file.Close();
	}

	::SelectObject(hMemDC, oldbmp);
	::DeleteObject(bitmap);
	::DeleteObject(hMemDC);
	::ReleaseDC(NULL, hScrDC);
}

'MFC > Bitmap' 카테고리의 다른 글

Bitmap.cpp  (0) 2013.08.16
리소스에서 BMP 이미지 불러오기  (0) 2013.08.09
Writing a window image to a BMP file  (0) 2013.08.08
Converting DDB to DIB  (0) 2013.08.08
memory dc to bitmap file  (0) 2013.08.08
Posted by 곰돌이짱
,