2 Bit BMP mit GDIP?

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

2 Bit BMP mit GDIP?

18 Jun 2020, 09:50

Huhu zusammen,

kurz und gut:
Ich habe ein GUI, in dem ein Picture Element ist, das aus bestimmten (CSV) Daten ein 2 Bit Bitmap anzeigt. Das funktioniert auch gut.

Nun ist meine Frage/Bitte:
Wie kann ich aus diesem Picture Element...
1) die Grafikdaten so ins Clipboard legen, dass ich sie mit Paste z.B. in Paint.Net einfügen kann?
2) Dieses Picture Element als (wichtig!) 2 Bit BMP speichern kann. 2 Bit deshalb, weil die Bilder nur schwarze und weiße Pixel haben und damit ich es nachher nciht nocmal mittels eines GFX Programmes konvertieren muss.

Es reicht mir völlig, wenn jemand grob erklärt, wie man dafür die GDIP Lib nutzt, denn ich werde aus den Pointern, etc. nicht so ganz schlau.


Danke im Voraus für Eure Tipps.

Gucky.
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

18 Jun 2020, 10:53

Moin Gucky,

für mich ist Schwarz|Weiß -> 0|1 -> 1 Bit. Wie kommst Du auf 2 Bit? In 2 Bit kann man vier Farben unterbringen.

Wenn Du etwas in einem Pic-Control darstellst, muss Du dafür eine Quelle in Form einer Bitmap haben. Wie entsteht die?

Zum Thema Clipboard schau Dir mal die Clipboard-Manager im englishen Forum an. SKAN hat bestimmt auch irgendwann einmal eine Funktion HBITMAPToClipboard() (oder ähnlich) eingestellt.
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

18 Jun 2020, 16:59

Huhu,

@ just me:
Hast natürlich Recht, ar blöd ausgedrückt.
Das ganze funktioniert im Prinzip so:
Ich habe eine Datei, in der die reinen Bits des Bildes im BMP Format stehen, also ohne jegliche Header, etc.
Ich weiß nur, dass die Bilder grundsätzlich in S/W sind und ich kenne Höhe und Breite in Pixeln.
Daraus habe ich mir eine Funktion gebastelt, die eben diese Pixel in einem PIC Gui Element setzt (schwarze und weiße Punkte).
Dieses fertige Bild möchte ich nun mit GDIP einerseits als BMP (1 Bit natürlich) speichern und auch per Copy & Paste z.B.
in andere Programme einfügen können.

Für die GDIP Lib habe ich bisher jedoch ausschließlich Beispiele gefunden (was auch funktioniert), die das Bild in mehr als 1 Bit
Farbtiefe als BMP speichern können. Ins Clipboard bekomme ich das halt noch nicht und als 1 Bit BMP.

Gucky.
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

19 Jun 2020, 01:46

Moin,
Gucky_87 wrote:Daraus habe ich mir eine Funktion gebastelt, die eben diese Pixel in einem PIC Gui Element setzt (schwarze und weiße Punkte).
Und eben darauf bezieht sich meine Frage: Wie entsteht die? Üblicherweise braucht man dafür eine Bitmap, wenn das stabil sein soll.
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

19 Jun 2020, 06:00

Ursprünglich kommen diese Bilder sicherlich aus BMPs, die in unsere Geräte eingespielt werden.
Dort liegen jedoch nur die REINEN Pixeldaten im 1 Bit BMP Format vor.
Ich möchte nun diese Daten nicht nur anzeigen, sondern auch die Möglichkeit haben, sie zu archivieren/bearbeiten. Daher meine Frage nach 1 Bit, denn als 2, 4, 8 ... 32 Bit müsste ich das erst wieder nach 1 Bit konvertieren.


Zu meiner Funktion:
Ich habe mir was gebastelt, das diese Daten, die üblicherweise von SD Karten kommen, eingelesen werden und dann quasi zeilenweise daraus per GDIP im Speicher ein BMP erzeugt wird.

Hier mal der Code dazu.

Code: Select all

      FILE := FileOpen(LOGOPICFILE, "r")
      WIDTH    := 384
      HEIGHT   := 130
      SPALTEN  := 48
      LOGO     := ""
      if(FILE.Length == 6240) Or (FILE.Length == 9360)
      {
        if (FILE.Length > 6240)
        {
          SPALTEN := 72
          WIDTH   := 576
          GuiControl, Main: Move, LOGOPIC   , % "X290 Y172 W243 H55"
        }
        else
        {
          GuiControl, Main: Move, LOGOPIC   , % "X290 Y172 W243 H82"
        }
        Loop, % File.Length
          LOGO .= Dec2Bin(asc(ReadFilePart(LOGOPICFILE, A_Index, 1)))

        FILE.Close()
      }
    }
    ; else
    ;  MsgBox, 8240, %PRGNAME% [v%PRGVER%] - Fehler, % "Das grafische Logo kann`nnicht geladen werden!", 10
  
    pBitmap := Gdip_CreateBitmap(Width, Height)
    G       := Gdip_GraphicsFromImage(pBitmap)
    Gdip_SetSmoothingMode(G, 0)
    pBrush  := Gdip_BrushCreateSolid(0xffffffff)
    Gdip_FillRectangle(G, pBrush, 0, 0, Width, Height)
    pBrush  := Gdip_BrushCreateSolid(0xff000000)
    Loop, %Height%
    {
      ZEILE := A_Index
      Loop, %SPALTEN%
      {
        SPALTE := A_Index
        POS := ((ZEILE - 1) * WIDTH) + ((SPALTE - 2) * 8) + 1
        PIX := SubStr(LOGO, POS, 8)
        if(PIX != "00000000")
        {
          Loop, 8
          {
            if (SubStr(PIX, A_Index, 1) = 1)
              Gdip_FillRectangle(G, pBrush, ((SPALTE - 1) * 8) + A_Index - 1, ZEILE - 1, 1, 1)
          }
        }
      }
    }
    Gdip_DeleteBrush(pBrush)
    hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
    GuiControl, Main: , LOGOPIC, HBITMAP:%hBitMap%
    ;Gdip_SetBitmapToClipboard(pBitmap)
    Gdip_SaveBitmapToFile(pBitmap, A_Desktop . "\Test.bmp")
    SetClipboardData(ahk_id LOGOPIC)

Was meinst Du mit "stabil"?
DieBidler sind alle exakt gleich groß, sie haben alle NUR schwarze und weiße Pixel, daher ist jedes Bild aufs Byte genau gleich lang. Oder emiinstest Du damit etwas anderes?

Gucky.
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

19 Jun 2020, 08:15

Code: Select all

    pBitmap := Gdip_CreateBitmap(Width, Height)
erzeugt eine 32-bittige Bitmap.
Kannst Du mal eine Datei einstellen, damit ich das mit GDI testen kann?
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

19 Jun 2020, 08:31

Sorry, wenn ich jetzt ganz blöd frage:
Wie kann ich eine Datei hier anhängen?

*schäm*

Gucky
BoBo
Posts: 3761
Joined: 13 May 2014, 17:15

Re: 2 Bit BMP mit GDIP?

19 Jun 2020, 09:08

Full Editor > unten den Tab "Attachments" anklicken ... :shh:
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

20 Jun 2020, 04:27

Hi,

Daten aus einer CSV-Datei kann man sehr wahrscheinlich auch aus einem Editor in eine Codebox kopieren.
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

25 Jun 2020, 03:28

Ahh ok, vielen Dank. Das mit den Attachments hab ich echt übersehehn.

Alsooooo...
Ich habe mal eine BMP Datei erstellt (1 Bit, s. u.) und die dazugehörige Datei angehängt, die ausschließich die Pixeldaten beinhaltet ohne sonstige Informationen.

ACHTUNG:
Benennt "Test.txt" bitte in "Test.bmp" um und "TMLOG1TB.TXT" in "TMLOG1TB.SDA".

in der *.SDA Datei liegen die "Rohdaten" der "Test.bmp", sprich NUR die reinen Pixelinformationen, ohne jegliche Headerdaten und in genau aus DIESEN Daten möchte ich nachher wieder ein 1 Bit BMP machen.
WIe gesagt, 32 Bit habe ich mit obiger Routine (vllt. etwas unschön?) hinbekommen, aber das herunterzurechnen, schaffe ich irgendwie nicht.

Gucky.
Attachments
Test.txt
(6.15 KiB) Downloaded 24 times
TMLOG1TB.TXT
(6.09 KiB) Downloaded 25 times
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

29 Jun 2020, 05:20

Moin,

die beiden Dateien sind interessant. Die SDA-Datei enthält einen "Spiegel" der BMP Rohdaten, soll heißen: in SDA steht 0 für Schwarz, in BMP für Weiß. (Bei der Erweiterung SDA klingelt es irgendwo tief in meinen vergrabenen Erinnerungen, es kommt aber nichts hoch.)
Es scheint mir gelungen zu sein, mit GDI (ohne +) eine Schwarzweißbitmap zu erstellen. Außerdem habe ich in meinem Fundus noch Routinen für das Abspeichern der BMP-Datei und die Übernahme ins Clipboard gefunden. Nach kleineren Anpassungen scheinen auch die zu tun. Ich weiß nicht mehr, wo ich die 'entwendet' habe. Ich glaube, die Originale stammen von SKAN.

Code: Select all

#NoEnv
SetBatchLines, -1
SetWorkingDir, %A_ScriptDir%

LogoPicFile := "TMLOG1TB.SDA"
If !(DataFile := FileOpen(LogoPicFile, "r")) {
   MsgBox, 16, Error!, Die Datei %LogoPicFile% konnte nicht geöffnet werden!
   ExitApp
}
If (DataFile.Length = 6240) {
   Width   := 384
   Height  := 130
   Spalten := 48
}
Else If (DataFile.Length = 9360) {
   Width   := 576
   Height  := 130
   Spalten := 72
}
Else {
   MsgBox, 16, Error!, Die Datei %LogoPicFile% ist fehlerhaft!
   DataFile.Close()
   ExitApp
}
DataFile.RawRead(PixelData, DataFile.Length)
HBM := CreateBM(PixelData, Width, Height)
DataFile.Close()
BitMapInfo(HBM)
SaveBM(HBM, "Test2.bmp")
Gui, Add, Text, , SDA:
Gui, Add, Pic, , HBITMAP:*%HBM%
Gui, Add, Text, , Original:
Gui, Add, Pic, , Test.bmp
Gui, Add, Text, , Kopie:
Gui, Add, Pic, , Test2.bmp
Gui, Show, , Bitmap
BM2Clipboard(HBM)
Return
GuiClose:
ExitApp
; ================================================================================================================================
BitMapInfo(HBM) {
   Static Size := (A_PtrSize = 8) ? 32  : 24
   VarSetCapacity(BM, Size, 0)
   DllCall("GetObject", "Ptr", HBM, "Int", Size, "Ptr", &BM)
   BW := NumGet(BM, 4, "Int")
   BH := NumGet(BM, 8, "Int")
   BBW := NumGet(BM, 12, "Int")
   BPL := NumGet(BM, 16, "UShort")
   BPP := NumGet(BM, 18, "UShort")
   MsgBox, Width: %BW%`nHeight: %BH%`nWidthBytes: %BBW%`nPlanes: %BPL%`nBitsPixel: %BPP%
}
; ================================================================================================================================
CreateBM(ByRef PixelData, Width, Height) {
   Static HBR := DllCall("CreateSolidBrush", "UInt", 0xFFFFFF, "UPtr")
   MDC := DllCall("CreateCompatibleDC", "Ptr", 0, "UPtr")
   MBM := DllCall("CreateCompatibleBitmap", "Ptr", MDC, "Int", Width, "Int", Height, "UPtr")
   OBM := DllCall("SelectObject", "Ptr", MDC, "Ptr", MBM, "UPtr")
   VarSetCapacity(RC, 16, 0)
   NumPut(Width, RC, 8, "Int")
   NumPut(Height, RC, 12, "Int")
   DllCall("FillRect", "Ptr", MDC, "Ptr", &RC, "Ptr", HBR)
   WidthBytes := Width // 8
   Bytes := WidthBytes * Height
   I := 0, X := 0, Y := 0
   Loop, %Bytes% {
      Loop, %WidthBytes% {
         If (B := NumGet(PixelData, I++, "UChar")) {
            S := 1 << 7
            Loop, 8 {
               If (B & S)
                  DllCall("SetPixel", "Ptr", MDC, "Int", X, "Int", Y, "UInt", 0x0)
               S >>= 1
               X++
            }
         }
         Else
            X += 8
      }
      X := 0, Y++
   }
   DllCall("SelectObject", "Ptr", MDC, "Ptr", OBM, "UPtr")
   DllCall("DeleteDC", "Ptr", MDC)
   Return MBM
}
; ================================================================================================================================
SaveBM(HBM, FilePath) {
   Static SizeBM := A_PtrSize = 8 ? 32 : 24           ; BITMAP
        , SizeBMFH := 14                              ; BITMAPFILEHEADER
        , SizeBMIH := 40                              ; BITMAPINFOHEADER
        , SizeDIB := A_PtrSize = 8 ? 104 : 84         ; DIBSECTION
   HDIB := DllCall("CopyImage", "Ptr", HBM, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x2000, "UPtr")
   VarSetCapacity(DIB, SizeDIB, 0)
   DllCall("GetObject", "Ptr", HDIB, "Int", SizeDIB, "Ptr", &DIB)
   Size := NumGet(DIB, A_PtrSize = 8 ? 52 : 44, "UInt")
   PicFile := FileOpen(FilePath, "w", "CP0")
   ; BITMAPFILEHEADER
   PicFile.Write("BM")                                ; bfType
   PicFile.WriteUInt(SizeBMFH + SizeBMIH + Size + 8)  ; bfSize
   PicFile.WriteUInt(0)                               ; bfReserved
   PicFile.WriteUInt(SizeBMFH + SizeBMIH + 8)         ; bfOffBits
   ; BITMAPINFOHEADER
   PicFile.RawWrite(&DIB + SizeBM, SizeBMIH)
   ; bmicolors
   PicFile.WriteUInt(0x000000)
   PicFile.WriteUInt(0xFFFFFF)
   ; bmBits
   PicFile.RawWrite(NumGet(DIB, A_PtrSize = 8 ? 24 : 20, "UPtr"), Size)
   PicFile.Close()
   DllCall("DeleteObject", "Ptr", HDIB)
}
; ================================================================================================================================
BM2Clipboard(HBM) {
   Static SizeOfBM := A_PtrSize = 8 ? 32 : 24     ; BITMAP
        , SizeOfBMFH := 14                        ; BITMAPFILEHEADER
        , SizeOfBMIH := 40                        ; BITMAPINFOHEADER
        , SizeOfDIB := A_PtrSize = 8 ? 104 : 84   ; DIBSECTION
   HDIB := DllCall("CopyImage", "Ptr", HBM, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x2000, "UPtr")
   VarSetCapacity(DIB, SizeOfDIB, 0)
   DllCall("GetObject", "Ptr", HDIB, "Int", SizeOfDIB, "Ptr", &DIB)
   Size := NumGet(DIB, A_PtrSize = 8 ? 52 : 44, "UInt")
   HBMP := DllCall("GlobalAlloc", "UInt", 2, "Ptr", SizeOfBMIH + Size + 8, "UPtr")
   PBMP := DllCall("GlobalLock", "Ptr", HBMP, "UPtr")
   DllCall("RtlMoveMemory", "Ptr", PBMP, "Ptr", &DIB + SizeOfBM, "Ptr", SizeOfBMIH)
   NumPut(0x000000, PBMP + SizeOfBMIH, "UINT")
   NumPut(0xFFFFFF, PBMP + SizeOfBMIH + 4, "UINT")
   DllCall("RtlMoveMemory", "Ptr", PBMP + SizeOfBMIH + 8, "Ptr", NumGet(DIB, A_PtrSize = 8 ? 24 : 20, "UPtr"), "Ptr", Size)
   DllCall("GlobalUnlock", "Ptr", HBMP)
   DllCall("OpenClipboard", "Ptr", 0)
   DllCall("EmptyClipboard")
   DllCall("SetClipboardData", "UInt", 8, "Ptr", HBMP)
   DllCall("CloseClipboard")
   DllCall("DeleteObject", "Ptr", HDIB)
}
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

30 Jun 2020, 08:30

Das ist große Klasse und ich sage, wie immer, gaaanz doll DANKEEEE.

Hab Dir ja er PM noch was geschrieben ;)

Gucky.
just me
Posts: 7298
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: 2 Bit BMP mit GDIP?

01 Jul 2020, 06:10

Moin Gucky,

danke für die Info. Ich habe noch rumgespielt und versucht, die inneren Strukturen besser zu verstehen und das Ganze für diesen speziellen Fall zu vereinfachen. Dabei sind diese Funktionen herausgekommen:

Code: Select all

; ================================================================================================================================
BM_CreateFromSDA(SDA_File) {
   Static Colors := 0x0000000000FFFFFF ; bmiColors[0] = 0x00FFFFFF, bmiColors[1] = 0x00000000)
   If !(DataFile := FileOpen(SDA_File, "r")) {
      MsgBox, 16, %A_ThisFunc%, Die Datei %SDA_File% konnte nicht geöffnet werden!
      Return 0
   }
   If (DataFile.Length <> 6240) && (DataFile.Length <> 9360) {
      MsgBox, 16, Error!, Die Datei %SDA_File% ist fehlerhaft!
      DataFile.Close()
      Return 0
   }
   Width := (DataFile.Length) = 6240 ? 384 : 576
   Height := 130
   DataFile.RawRead(PixelData, DataFile.Length)
   DataFile.Close()
   HDC := DllCall("CreateCompatibleDC", "Ptr", 0, "UPtr")
   HBM := DllCall("CreateBitmap", "Int", Width, "Int", Height, "UInt", 1, "UInt", 1, "Ptr", &PIXELDATA, "UPtr")
   HBM := DllCall("CopyImage", "Ptr", HBM, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x2008, "UPtr")
   OBM := DllCall("SelectObject", "Ptr", HDC, "Ptr", HBM, "UPtr")
   DllCall("SetDIBColorTable", "Ptr", HDC, "UInt", 0, "UInt", 2, "Int64P", Colors)
   DllCall("SelectObject", "Ptr", HDC, "Ptr", OBM)
   DllCall("DeleteDC", "Ptr", HDC)
   VarSetCapacity(PixelData, 0)
   Return HBM
}
; ================================================================================================================================
BM_Copy(HBM) {
   HCOPY := DllCall("CopyImage", "Ptr", HBM, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x0000, "UPtr")
   DllCall("OpenClipboard", "Ptr", 0)
   DllCall("EmptyClipboard")
   DllCall("SetClipboardData", "UInt", 2, "Ptr", HCOPY)
   DllCall("CloseClipboard")
}
; ================================================================================================================================
BM_Save(HBM, FilePath) {
   Static SizeBM := A_PtrSize = 8 ? 32 : 24           ; BITMAP
        , SizeBMFH := 14                              ; BITMAPFILEHEADER
        , SizeBMIH := 40                              ; BITMAPINFOHEADER
        , SizeDIB := A_PtrSize = 8 ? 104 : 84         ; DIBSECTION
   VarSetCapacity(DIB, SizeDIB, 0)
   DllCall("GetObject", "Ptr", HBM, "Int", SizeDIB, "Ptr", &DIB)
   Size := NumGet(DIB, A_PtrSize = 8 ? 52 : 44, "UInt")
   PicFile := FileOpen(FilePath, "w", "CP0")
   ; BITMAPFILEHEADER
   PicFile.Write("BM")                                ; bfType
   PicFile.WriteUInt(SizeBMFH + SizeBMIH + Size + 8)  ; bfSize
   PicFile.WriteUInt(0)                               ; bfReserved
   PicFile.WriteUInt(SizeBMFH + SizeBMIH + 8)         ; bfOffBits
   ; BITMAPINFOHEADER
   PicFile.RawWrite(&DIB + SizeBM, SizeBMIH)
   ; bmicolors
   PicFile.WriteInt64(0xFFFFFF)
   ; bmBits
   PicFile.RawWrite(NumGet(DIB, A_PtrSize = 8 ? 24 : 20, "UPtr"), Size)
   PicFile.Close()
}
Für mich sieht das 'übersichtlicher' aus, weil mehr API-Funktionen genutzt werden und deshalb auf einige NumPut() Aufrufe verzichtet werden kann. Wenn es aber um maximale Performance geht, mag in Teilen 'langsamer' sein.
User avatar
Gucky_87
Posts: 344
Joined: 03 Jul 2014, 05:09

Re: 2 Bit BMP mit GDIP?

01 Jul 2020, 07:25

Ob das nun 1 oder 2 Sekunden dauert, kratzt mich nicht.
Wichtiger ist, dass es abgeeigt wird und dass man die Grafik als S/W BMP spiechern kann.

Ein dices Lobm dass Du Dich dafür so ins Zeug legst. VIELEN Dank!

Gucky.

Return to “Ich brauche Hilfe”

Who is online

Users browsing this forum: No registered users and 3 guests