2009-07-22 37 views
6

Tôi cần phải tạo đối tượng Bitmap sử dụng byte thô biểu thị dữ liệu bitmap đơn sắc. Trên khung làm việc đầy đủ, tôi đang làm như sau:Tạo bitmap đơn sắc trong Compact Framework

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed) 
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); 
// Write my data into bmpData.Scan0 
bmp.UnlockBits(bmpData); 

Thật không may, Khung nhỏ gọn không có giá trị enum PixelFormat.Format8bppIndexed. Vậy làm thế nào tôi có thể thực hiện điều này trên CF? Điều duy nhất tôi có thể nghĩ đến là tự tạo tiêu đề tập tin bitmap cho chính mình và ghi nó cùng với dữ liệu vào một Stream và sau đó xây dựng một đối tượng Bitmap với đối tượng Stream.

Ý tưởng?

Trả lời

0

Trong thư viện OpenNetCf Khung thiết bị thông minh (có phiên bản miễn phí), chúng có lớp Bitmap riêng (BitmapEx). Trong khi tôi đã không thử những gì bạn đang cố gắng làm, bạn có thể kiểm tra việc thực hiện của họ. (Lưu ý: Tôi phải làm điều này trong tuần tới, vì vậy tôi có thể sẽ cập nhật sau này)

+0

Tôi đã xem OpenNETCF nhưng dựa trên cùng một enum. Nhìn vào cách họ thực hiện một số lớp Bitmap có thể sẽ hữu ích vì tôi khá chắc chắn tôi sẽ cần phải tự xây dựng tiêu đề bản thân mình. :( – Jason

7

Dưới đây là một số mã có thể giúp:

const int XPelsPerMeter = 0xb12; // 72 ppi, 96 would work well too 
    const int YPelsPerMeter = 0xb12; 
    const int Gptr = 0x40; 
    const int Srccopy = 0x00CC0020; 


    struct BITMAPFILEHEADER 
    { 
    public ushort bfType; 
    public uint bfSize; 
    public ushort bfReserved1; 
    public ushort bfReserved2; 
    public uint bfOffBits; 
    } 

    struct BITMAPINFOHEADER 
    { 
    public uint biSize; 
    public int biWidth; 
    public int biHeight; 
    public ushort biPlanes; 
    public ushort biBitCount; 
    public uint biCompression; 
    public uint biSizeImage; 
    public int biXPelsPerMeter; 
    public int biYPelsPerMeter; 
    public uint biClrUsed; 
    public uint biClrImportant; 
    } 

    public static byte[] GetByteArray(Bitmap bitmap) 
    { 
    IntPtr hbm = bitmap.GetHbitmap(); // this is step (1) 
    IntPtr sdc = GetDC(IntPtr.Zero);  // First we obtain the DC for the screen 
    // Next, create a DC for the original hbitmap 
    IntPtr hdc = CreateCompatibleDC(sdc); 
    SelectObject(hdc, hbm); 

    byte[] arrayBytes = CreateBinary(hdc, bitmap.Height, bitmap.Width); 

    // Finally some cleanup. 
    DeleteDC(hdc); 
    ReleaseDC(IntPtr.Zero, sdc); 
    DeleteObject(hbm); 

    return arrayBytes; 
    } 

    static int WIDTHBYTES(int bits) 
    { 
    return ((((bits) + 31)/32) * 4); 
    } 

    private static byte[] CreateBinary(IntPtr hDc, int height, int width) 
    { 
    IntPtr hMemDc = CreateCompatibleDC(hDc); 

    int cb = 0; 

    BITMAPINFOHEADER bi = new BITMAPINFOHEADER(); 
    bi.biSize = (uint)Marshal.SizeOf(bi); 
    bi.biBitCount = 1; // Creating RGB bitmap. The following three members don't matter 
    bi.biClrUsed = 2; 
    bi.biClrImportant = 2; 
    bi.biCompression = 0; 
    bi.biHeight = height; 
    bi.biWidth = width; 
    bi.biPlanes = 1; 
    cb = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; 
    bi.biSizeImage = (uint)cb; 
    bi.biXPelsPerMeter = XPelsPerMeter; 
    bi.biYPelsPerMeter = YPelsPerMeter; 

    IntPtr pBits = IntPtr.Zero; 
    //Allocate memory for bitmap bits 
    IntPtr pBi = LocalAlloc(Gptr, bi.biSize); 
    // Not sure if this needed - simply trying to keep marshaller happy 
    Marshal.StructureToPtr(bi, pBi, false); 
    //This will return IntPtr to actual DIB bits in pBits 
    IntPtr hBmp = CreateDIBSection(hDc, pBi, 0, ref pBits, IntPtr.Zero, 0); 
    //Marshall back - now we have BITMAPINFOHEADER correctly filled in 
    //Marshal.PtrToStructure(pBI, bi); 
    BITMAPINFOHEADER biNew = (BITMAPINFOHEADER)Marshal.PtrToStructure(pBi, typeof(BITMAPINFOHEADER)); 

    //Usual stuff 
    IntPtr hOldBitmap = SelectObject(hMemDc, hBmp); 
    //Grab bitmap 
    BitBlt(hMemDc, 0, 0, bi.biWidth, bi.biHeight, hDc, 0, 0, Srccopy); 
    // Allocate memory for a copy of bitmap bits 
    byte[] RealBits = new byte[cb]; 
    // And grab bits from DIBSestion data 
    Marshal.Copy(pBits, RealBits, 0, cb); 

    // This simply creates valid bitmap file header, so it can be saved to disk 
    BITMAPFILEHEADER bfh = new BITMAPFILEHEADER(); 
    uint colorSize = 2 * 4;//2 colors for B&W, 4 bytes (RGBQUAD) 
    uint sizeofBinfo = 0x36 + colorSize;//original 
    //sizeofBINFO = (uint)Marshal.SizeOf(bi);//sorin 
    //bfh.bfSize = (uint)cb + 0x36; // Size of header + size of BITMAPINFOHEADER size of bitmap bits 
    bfh.bfSize = (uint)(cb + sizeofBinfo); 
    bfh.bfType = 0x4d42; //BM 
    bfh.bfOffBits = sizeofBinfo; // 
    int HdrSize = 14; 
    byte[] header = new byte[HdrSize]; 
    BitConverter.GetBytes(bfh.bfType).CopyTo(header, 0); 
    BitConverter.GetBytes(bfh.bfSize).CopyTo(header, 2); 
    BitConverter.GetBytes(bfh.bfOffBits).CopyTo(header, 10); 

    //Allocate enough memory for complete bitmap file 
    byte[] data = new byte[cb + bfh.bfOffBits]; 
    //BITMAPFILEHEADER 
    header.CopyTo(data, 0); 

    //BITMAPINFOHEADER 
    header = new byte[Marshal.SizeOf(bi)]; 
    IntPtr pHeader = LocalAlloc(Gptr, (uint)Marshal.SizeOf(bi)); 
    Marshal.StructureToPtr(biNew, pHeader, false); 
    Marshal.Copy(pHeader, header, 0, Marshal.SizeOf(bi)); 
    LocalFree(pHeader); 

    header.CopyTo(data, HdrSize); 

    //set black color as second color from color table 
    byte[] colors = new byte[10]; 
    colors[4] = 255; 
    colors[5] = 255; 
    colors[6] = 255; 

    colors.CopyTo(data, (int)bfh.bfOffBits - (int)colorSize); 

    //Bitmap bits 
    RealBits.CopyTo(data, (int)bfh.bfOffBits); 

    DeleteObject(SelectObject(hMemDc, hOldBitmap)); 
    DeleteDC(hMemDc); 

    return data; 
    } 

    [DllImport("coredll.dll")] 
    public static extern bool DeleteObject(IntPtr hObject); 

    [DllImport("coredll.dll")] 
    public static extern int InvalidateRect(IntPtr hwnd, IntPtr rect, int bErase); 

    [DllImport("coredll.dll")] 
    public static extern IntPtr GetDC(IntPtr hwnd); 

    [DllImport("coredll.dll")] 
    public static extern IntPtr CreateCompatibleDC(IntPtr hdc); 

    [DllImport("coredll.dll")] 
    public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); 

    [DllImport("coredll.dll")] 
    public static extern int DeleteDC(IntPtr hdc); 

    [DllImport("coredll.dll")] 
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); 

    [DllImport("coredll.dll")] 
    public static extern int BitBlt(IntPtr hdcDst, int xDst, int yDst, int w, int h, IntPtr hdcSrc, int xSrc, int ySrc, int rop); 

    [DllImport("coredll.dll")] 
    private static extern IntPtr LocalAlloc(uint flags, uint cb); 

    [DllImport("coredll.dll")] 
    private static extern IntPtr LocalFree(IntPtr hMem); 

    [DllImport("coredll.dll")] 
    private static extern IntPtr CreateDIBSection(IntPtr hdc, IntPtr hdr, uint colors, ref IntPtr pBits, IntPtr hFile, uint offset); 
} 

Để lưu nó vào một tập tin thực hiện như sau:

byte[] data = BWImage.GetByteArray(bitmap); 
FileStream fs = new FileStream("BW.bmp", FileMode.Create); 
fs.Write(data, 0, data.Length); 
fs.Flush(); 
fs.Close(); 
+0

Wow, những gì một nỗi đau trong mông.Tôi không chắc chắn điều này sẽ chính xác làm việc cho những gì tôi cần kể từ khi tôi không thể gọi GetByteArray (bitmap) (Tôi không có một Bitmap nào được nêu ra, tôi cần phải tạo một Tôi nghĩ rằng tôi cần phải gọi CreateDIBSection và sau đó ghi dữ liệu của tôi vào pBits ... – Jason

+0

Cảm ơn, đã lưu cổ của tôi! –

Các vấn đề liên quan