2009-12-02 10 views
6

Ich habe ein Bild einer Signatur, die ich als 1 bpp Bitmap speichern möchte, um Speicherplatz zu sparen. Das vollständige .NET Framework hat das Enum PixelFormat.Format1bppIndexed, aber das .NET Compact Framework unterstützt es nicht.Konvertieren von Bild zu 1 bpp Bitmap in. NET kompaktes Framework

Hat jemand einen Weg gefunden, dies in Windows Mobile zu erreichen?

Antwort

6

Danke, dass Sie mich in die richtige Richtung zeigen, ctacke. Ich konnte die Bitmap Klasse nicht verwenden, um die Bilddaten zu speichern. Es warf ständig OutOfMemoryException. Ich habe das Bitmap mit einem BinaryWriter geschrieben, wie Sie es vorgeschlagen haben.

Meine End-Lösung liefert ein Byte-Array, mit denen Sie wählen können, um die Platte zu schreiben, in einer Datenbank speichern, übertragen, usw.

class ImageHelper 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    public struct BITMAPINFOHEADER 
    { 
     public BITMAPINFOHEADER(ushort bpp, int height, int width) 
     { 
      biBitCount = bpp; 
      biWidth = width; 
      biHeight = height; 

      biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); 
      biPlanes = 1; // must be 1 
      biCompression = 0; // no compression 
      biSizeImage = 0; // no compression, so can be 0 
      biXPelsPerMeter = 0; 
      biYPelsPerMeter = 0; 
      biClrUsed = 0; 
      biClrImportant = 0; 
     } 

     public void Store(BinaryWriter bw) 
     { 
      Store(bw, null); 
     } 

     public void Store(BinaryWriter bw, uint[] colorPalette) 
     { 
      // Must maintain order for file writing 
      bw.Write(biSize); 
      bw.Write(biWidth); 
      bw.Write(biHeight); 
      bw.Write(biPlanes); 
      bw.Write(biBitCount); 
      bw.Write(biCompression); 
      bw.Write(biSizeImage); 
      bw.Write(biXPelsPerMeter); 
      bw.Write(biYPelsPerMeter); 
      bw.Write(biClrUsed); 
      bw.Write(biClrImportant); 

      // write color palette if 8 bpp or less 
      if (biBitCount <= 8) 
      { 
       if (colorPalette == null) 
        throw new ArgumentNullException("bpp is 8 or less, color palette is required"); 

       uint paletteCount = BITMAPFILEHEADER.CalcPaletteSize(biBitCount)/4; 
       if (colorPalette.Length < paletteCount) 
        throw new ArgumentException(string.Format("bpp is 8 or less, color palette must contain {0} colors", paletteCount)); 

       foreach (uint color in colorPalette) 
        bw.Write(color); 
      } 
     } 

     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; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct BITMAPFILEHEADER 
    { 
     public BITMAPFILEHEADER(BITMAPINFOHEADER info, out uint sizeOfImageData) 
     { 
      bfType = 0x4D42; // Microsoft supplied value to indicate Bitmap 'BM' 
      bfReserved1 = 0; 
      bfReserved2 = 0; 

      // calculate amount of space needed for color palette 
      uint paletteSize = CalcPaletteSize(info.biBitCount); 

      bfOffBits = 54 + paletteSize; // default value + paletteSize 

      // calculate size of image 
      sizeOfImageData = (uint)(CalcRowSize(info.biWidth * info.biBitCount) * info.biHeight); 
      bfSize = sizeOfImageData + bfOffBits; 
     } 

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

     public static uint CalcPaletteSize(int bpp) 
     { 
      // 8 bpp or less, needs an uint per color 
      if (bpp <= 8) 
       return 4 * (uint)Math.Pow(2, bpp); 

      // no palette needed for 16bpp or higher 
      return 0; 
     } 

     public void Store(BinaryWriter bw) 
     { 
      // Must maintain order for file writing 
      bw.Write(bfType); 
      bw.Write(bfSize); 
      bw.Write(bfReserved1); 
      bw.Write(bfReserved2); 
      bw.Write(bfOffBits); 
     } 

     public ushort bfType; 
     public uint bfSize; 
     public short bfReserved1; 
     public short bfReserved2; 
     public uint bfOffBits; 
    } 

    public static byte[] GetByteArray(Bitmap image) 
    { 
     IntPtr hbmOld; 
     IntPtr hBitmap; 
     IntPtr hDC; 

     // create infoheader 
     BITMAPINFOHEADER bih = new BITMAPINFOHEADER(1, image.Height, image.Width); 
     // set black and white for 1 bit color palette 

     // create fileheader and get data size 
     uint sizeOfImageData; 
     BITMAPFILEHEADER bfh = new BITMAPFILEHEADER(bih, out sizeOfImageData); 

     // create device context in memory 
     hDC = Win32.CreateCompatibleDC(IntPtr.Zero); 

     // create a 1 bpp DIB 
     IntPtr pBits = IntPtr.Zero; 
     hBitmap = Win32.CreateDIBSection(hDC, ref bih, 1, ref pBits, IntPtr.Zero, 0); 

     // selet DIB into device context 
     hbmOld = Win32.SelectObject(hDC, hBitmap); 

     using (Graphics g = Graphics.FromHdc(hDC)) 
     { 
      g.DrawImage(image, 0, 0); 
     } 

     byte[] imageData = new byte[sizeOfImageData]; 
     byte[] fileData; 

     using (MemoryStream ms = new MemoryStream((int)bfh.bfSize)) 
     { 
      using (BinaryWriter w = new BinaryWriter(ms)) 
      { 
       bfh.Store(w); 
       // store bitmapinfoheader with 1 bpp color palette for black and white 
       bih.Store(w, new uint[] { (uint)0x0, (uint)0xffffff }); 

       // copy image data into imageData buffer 
       Marshal.Copy(pBits, imageData, 0, imageData.Length); 

       // write imageData to stream 
       w.Write(imageData); 

       w.Close(); 
      } 

      fileData = ms.GetBuffer(); 
      ms.Close(); 
     } 

     // select old object 
     if (hbmOld != IntPtr.Zero) 
      Win32.SelectObject(hDC, hbmOld); 

     // delete memory bitmap 
     if (hBitmap != IntPtr.Zero) 
      Win32.DeleteObject(hBitmap); 

     // delete memory device context 
     if (hDC != IntPtr.Zero) 
      Win32.DeleteDC(hDC); 

     return fileData; 
    } 
} 
+0

gut gemacht, Jack – ctacke

+0

Angenommen, Sie wissen, wo Sie das Win32.DeleteObject (und andere Win32-Methoden) erhalten? Ich habe ein Win32-Projekt in meiner Lösung, aber es hat diese Methoden nicht. Haben Sie sie selbst gerollt (oder können Sie sich nach so langer Zeit erinnern?) – Vaccano

+2

Sie sind P/Invoke Funktionen von coredll.dll. Beispiel: [DllImport ("coredll.dll")] öffentliche statische extern void DeleteObject (IntPtr hObj); – jnosek

1

Das Erstellen und Speichern einer Bitonal-Bitmap ist selbst im vollständigen Framework problematisch.

Ich schrieb zuvor einen Artikel zu diesem Thema beteiligt.

http://www.codeproject.com/KB/GDI-plus/BitonalImageConverter.aspx

revisited ich diesen Code im Kontext des kompakten Rahmen und entdeckt, wie Sie, dass der ENUM-Wert nicht existiert hat, so dass Sie nicht ein Schwarzweißbild von Grund auf neu erstellen können.

Ich würde gerne wissen, ob Sie bereits vorhandene bitonale Bilder in das kompakte Framework laden können. Wenn Sie bereits vorhandene Bitonal-Bitmaps laden können, ist es möglicherweise möglich, auf eine niedrigere Ebene zu wechseln und das Bitmap-Bildformat direkt auf Datenträger oder einen Speicherstream zu schreiben, anstatt die GDI + -Objekte zu verwenden. Dies wäre jedoch nicht trivial .

11

Ich musste dies in der Vergangenheit tun, um schwarze & weiße Berichte zu erzeugen, die über Bluetooth gedruckt wurden (Farb- oder Graustufenbilder waren zu groß für den Puffer des Druckers). Es stellte sich heraus, dass ich die Bilder mit nativem Code erstellen musste.

Hier ist ein Ausschnitt:

private void CreateUnmanagedResources() 
{ 
    // for safety, clean up anything that was already allocated 
    ReleaseUnmanagedResources(); 

    bih = new BITMAPINFOHEADER(); 
    bih.biBitCount = 1; 
    bih.biClrImportant = 0; 
    bih.biClrUsed = 0; 
    bih.biCompression = 0; 
    bih.biHeight = m_cy; 
    bih.biPlanes = 1; 
    bih.biSize = (uint)(Marshal.SizeOf(typeof(BITMAPINFOHEADER)) - 8); 
    bih.biSizeImage = 0; 
    bih.biWidth = m_cx; 
    bih.biXPelsPerMeter = 0; 
    bih.biYPelsPerMeter = 0; 
    bih.clr2 = 0xffffff; 
    bih.clr1 = 0x0; 

    hDC = Win32.CreateCompatibleDC(IntPtr.Zero); 
    pBits = IntPtr.Zero; 
    hBitmap = Win32.CreateDIBSection(hDC, bih, 1, ref pBits, IntPtr.Zero, 0); 
    hbmOld = Win32.SelectObject(hDC, hBitmap); 
} 

private void ReleaseUnmanagedResources() 
{ 
    if (hbmOld != IntPtr.Zero) 
     Win32.SelectObject(hDC, hbmOld); 

    if(hBitmap != IntPtr.Zero) 
     Win32.DeleteObject(hBitmap); 

    if (hDC != IntPtr.Zero) 
     Win32.DeleteDC(hDC); 
} 

habe ich dann Graphics.FromHdc ein verwalteter Grafiken erhalten einwenden, dass ich den Bericht auf malen konnte.

Ich habe mit einem BinaryWriter gespeichert, aber das war in CF 1.0 Tage, als die Bitmap-Klasse kein Speichern hatte, so dass Sie frei und klar dort sind.

+0

Vielen Dank für mich in die richtige Richtung. Ich entwickelte eine Lösung (siehe unten), die auf Ihrem Snippet aufbaut und ein Bitmap-Objekt in einen 1-Bit-Bitmap-Byte-Stream konvertiert. – jnosek