Guten Tag,
vor einigen Monaten habe ich mit autoit angefangen und schreibe seit dem funktionale(*) Programme für den Alltag.
*Umschreibung für unübersichtliche Codewurst die ich in meiner Freizeit schnell schreibe.
Was macht das Programm?
Das Programm erzeugt aus ganz vielen kleinen Bildern ein großes ganzes Bild.
Programmablauf
- Ein Hauptbild wird ausgewählt welches von weitem erkennbar sein soll (sollte so 128x128 sein Seitenformat ist egal)
- Als Vorlage wird ein Album mit jpg Fotos ausgewählt (Seitenformat sollte 1 zu 1 sein)
- Das Album wird auf eine vom Benutzer vorgegebene Größe skaliert (Aktuell 64x64) und unter Album rescale gespeichert
- Jeder Pixel und Position des Hauptbild wird zwischen gespeichert und wird durch ein kleines zufälligtes Foto aus dem Album rescale neu zusammengesetzt
- jedes Kleine Foto bekommt eine Umrandung der jeweiligen ermittelten Pixelfarbe. Transparenz und Dicke der Umrandung lässt sich einstellen
- zusätzlich lässt sich jedes kleine Bild mit der jeweiligen ermittelten Farbe und einer Transparenz einfärben, von weiten sieht es einfach besser aus.
Warum das ganze?
Die Grundidee habe ich aus einem Foto, dass ich mal über Whatsapp bekommen habe. (Kann ich aus Jugendschutzgründen nicht posten)
Mein Ziel ist es für Valentinstag eine große Pärchen Fotocollage zu erstellen und auf Leinwand,Poster oder Foto zu bringen.
Probleme
Bei einem Hauptbild mit 128x128 Pixel wird jeder Pixel mit 64x64 Bildern aufgefüllt.
Die Ausgabe hat eine Auflösung von 8192x8192. (128*64) als jpg ca 8MB weshalb ich das hier nur verkleinert hochladen konnte.
Keine Ahnung ob sich so etwas überhaupt als Poster in A4 oder A3 in einer vernünftigen DPI ausdrucken lässt, vielleicht hat jemand von euch Ideen und Anregungen Hab noch bis Dienstag Zeit.
Luxusproblem: Das Programm ist relativ lahm und braucht für die o.g Auflösung ca 2 Minuten.
Paar Beispiele
GUI:
Beispiel.jpg
Ausgabe: (50% skaliert)
1.jpg
Etwas näher dran. (auch 50% skaliert)
2.jpg
Wenn ich was Zeit finde mach ich den Code vorzeigbar und veröffentliche den bei Interesse auch hier.
EDIT 2
Neues in Version 1.1
- Das generieren dauert nur noch wenige Sekunden, THX @ UEZ!
- Neue Option "Keine identischen Bilder nebeneinander"
- Die Minibilder haben jetzt können jetzt gedreht oder gespiegelt eingesetzt werden
- Menü flackert nicht mehr
- Auflösung der Ausgabe wird angezeigt
- Paar Bugfixes
DoTo
- Schöneres GUI erstellen
- Minibilder in Format 2:3 3:2 erlauben (Aktuell leider nur 1:1)
- Keine identischen Bilder übereinander!
- Quellcode einheitlich machen und aufräumen.
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GDIPlus.au3> ;Für _GDIPlus_Startup() notwendig, Bildmanipulation!
#include <Timers.au3> ; Für _Timer_Init() notwendig,Anzeige der Dauer in Sekunden
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <File.au3>
#include <WinAPI.au3>
Opt("GUIOnEventMode", 1) ; Wird für GUICtrlSetOnEvent benoetigt!
Local $hGUI = GUICreate("PIC in PIC Generator", 600, 600) ;,BitOR($WS_HSCROLL,$WS_VSCROLL))
Global $idSlider_Filter_Transparenz = GUICtrlCreateSlider(10, 300, 200, 20)
GUICtrlSetLimit(-1, 255, 0) ; change min/max value
GUICtrlSetData(-1, 79)
Global $idLabel_Filter_Transparenz = GUICtrlCreateLabel("Filter Transparenz", 210, 300, 100, 30)
Global $idCheckbox_SamePicture = GUICtrlCreateCheckbox("Identische Bilder nebeneinander erlauben?", 10, 230, 250, 20)
Global $idRadio_No_Rotation = GUICtrlCreateRadio("Keine Rotation", 350, 240, 120, 20)
GUICtrlSetState(-1, $GUI_CHECKED)
Global $idRadio_Rotation = GUICtrlCreateRadio("Mit zufälliger Rotation", 350, 270, 120, 20)
Global $idRadio_Mirror = GUICtrlCreateRadio("Zufälliges Spiegeln", 350, 300, 120, 20)
Global $idSlider_Frame_width = GUICtrlCreateSlider(500, 350, 100, 20)
GUICtrlSetLimit(-1, 32, 0) ; change min/max value
GUICtrlSetData(-1, 5)
Global $idLabel_Frame_width = GUICtrlCreateLabel("Frame breite in Pixel", 350, 350, 100, 30)
Global $idSlider_Frame_Transparenz = GUICtrlCreateSlider(10, 350, 200, 20)
GUICtrlSetLimit(-1, 255, 0) ; change min/max value
GUICtrlSetData(-1, 127)
Global $idLabel_Frame_Transparenz = GUICtrlCreateLabel("Frame Transparenz", 210, 350, 100, 30)
Local $idwidth = GUICtrlCreateInput("64", 10, 380, 40, 20)
GUICtrlCreateLabel("Breite x Hoehe in Pixel", 60, 385, 100, 30)
Local $idLabel_Outputresolution = GUICtrlCreateLabel(" Aufloesung der Ausgabe = ", 160, 385, 500, 30)
Local $label_Vorlage = GUICtrlCreateLabel("", 0, 400, 300) ; first cell 70 width
Local $idFile = GUICtrlCreateInput(@ScriptDir & "\Vorlage\vorlage.png", 0, 420, 400, 30)
Local $idBtnOpenFile = GUICtrlCreateButton("Vorlage auswählen [oeFFNEN]", 410, 420, 190, 30)
Local $label_Album = GUICtrlCreateLabel("", 0, 440, 300) ; first cell 70 width
Local $idFile_Album = GUICtrlCreateInput(@ScriptDir & "\Album\", 0, 460, 400, 30)
Local $idBtnOpenFile_Album = GUICtrlCreateButton("Album auswählen [oeFFNEN]", 410, 460, 190, 30)
$BtnGen = GUICtrlCreateButton("Generieren", 0, 510, 400, 30)
Local $idProgressbar1 = GUICtrlCreateProgress(20, 550, 560, 20)
Local $label_Progress = GUICtrlCreateLabel("ERROR", 0, 580, 580) ; first cell 70 width
GUISetState(@SW_SHOW)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
GUICtrlSetOnEvent($BtnGen, "Bild_Zusammenbauen")
GUICtrlSetOnEvent($idBtnOpenFile, "SelectFileVorlage")
GUICtrlSetOnEvent($idBtnOpenFile_Album, "SelectFileAlbum")
Local $sSlider_Transparenz_old, $sSlider_Filter_Transparenz_old, $idSlider_Frame_width_old
While 1
Sleep(30)
If $sSlider_Transparenz_old <> GUICtrlRead($idSlider_Frame_Transparenz) Then
GUICtrlSetData($idLabel_Frame_Transparenz, "Frame Transparenz " & $idSlider_Frame_Transparenz & "/" & 255 & " HEX 0x" & Hex(GUICtrlRead($idSlider_Frame_Transparenz), 2))
EndIf
$sSlider_Transparenz_old = GUICtrlRead($idSlider_Frame_Transparenz)
If $sSlider_Filter_Transparenz_old <> GUICtrlRead($idSlider_Filter_Transparenz) Then
GUICtrlSetData($idLabel_Filter_Transparenz, "Filter Transparenz " & $idSlider_Filter_Transparenz & "/" & 255 & " HEX 0x" & Hex(GUICtrlRead($idSlider_Filter_Transparenz), 2))
EndIf
$sSlider_Filter_Transparenz_old = GUICtrlRead($idSlider_Filter_Transparenz)
If $idSlider_Frame_width_old <> GUICtrlRead($idSlider_Frame_width) Then
GUICtrlSetData($idLabel_Frame_width, "Frame breite in Pixel " & $idSlider_Frame_width & "/" & 32 & " HEX 0x" & Hex(GUICtrlRead($idSlider_Frame_width), 2))
EndIf
$idSlider_Frame_width_old = GUICtrlRead($idSlider_Frame_width)
WEnd
Func _get_HEX_Transparenz($id)
$iHEX_Transparenz = GUICtrlRead($id)
$iHEX_Transparenz = "0x" & Hex($iHEX_Transparenz, 2)
Return ($iHEX_Transparenz)
EndFunc ;==>_get_HEX_Transparenz
Func _Exit()
Exit
EndFunc ;==>_Exit
Func _IsChecked($idControlID)
Return BitAND(GUICtrlRead($idControlID), $GUI_CHECKED)
EndFunc ;==>_IsChecked
Local $idMsg
Func Bild_Zusammenbauen()
_PIC_scale(GUICtrlRead($idFile_Album))
$idFile_Album_rescale = @ScriptDir & "\Album rescale\"
_GDIPlus_Startup() ; Load PNG image
Local $hImage = _GDIPlus_ImageLoadFromFile(GUICtrlRead($idFile))
Local $iImageHeight = _GDIPlus_ImageGetHeight($hImage)
Local $iImageWidth = _GDIPlus_ImageGetWidth($hImage)
;Vorlage im GUI anzeigen! Bilder wieder freigeben! iX und iY gibt an wo das Bild im Interface dargestellt werden soll.
Local $iX = 0 ; Draw PNG image
Local $iY = 0
Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Local $bitmap_from_file
_GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, $iY)
Local $iImageWidth_Pixel_Pic = GUICtrlRead($idwidth) ;_GDIPlus_ImageGetWidth($hImage)
Local $iImageHeight_Pixel_Pic = GUICtrlRead($idwidth) ;_GDIPlus_ImageGetHeight($hImage)
Local $iCounter = 1
Local $hStarttime = _Timer_Init()
Local $iPercent, $iTime, $iRestzeit
Local $iSaveOld
; Aufloesung der Ausgabe bestimmen = Vorlage Hoehe * Hoehe Pixel Pic = Hoehe Ausgabe in Pixel, analog dazu die Breite
Local Const $width = $iImageWidth * $iImageWidth_Pixel_Pic
Local Const $height = $iImageHeight * $iImageHeight_Pixel_Pic
Local $hwnd = GUICreate("Clone Y", $width, $height)
Local $graphics = _GDIPlus_GraphicsCreateFromHWND($hwnd)
Local $bitmap = _GDIPlus_BitmapCreateFromGraphics($width, $height, $graphics)
Local $backbuffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
$iFrame_Transparenz = _get_HEX_Transparenz($idSlider_Frame_Transparenz)
$iFilter_Transparenz = _get_HEX_Transparenz($idSlider_Filter_Transparenz)
$iFilter_Frame_width = GUICtrlRead($idSlider_Frame_width)
$iFilelist = _FileListToArray($idFile_Album_rescale)
Local $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage) ;get width and height of the image
Local $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, BitOR($GDIP_ILMWRITE, $GDIP_ILMREAD), $GDIP_PXF32RGB) ;locks a portion of a bitmap for reading and writing. More infor at http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx
Local $iScan0 = DllStructGetData($tBitmapData, "Scan0") ;get scan0 (pixel data) from locked bitmap
Local $tPixel = DllStructCreate("int[" & $iW * $iH & "];", $iScan0)
Local $iPixel, $iRowOffset,$iSave_old
Local $aRandom[2] = [0, 4] ; 0 = keine Rotation 4= spiegeln! 90° 270° 180° gedreht sieht nicht gut aus.
For $i = 0 To $iImageHeight - 1 Step 1 ; Y Achse pro Pixel ein Bild generieren!
$iRowOffset = $i * $iW + 1
For $j = 0 To $iImageWidth - 1 Step 1 ; X Achse pro Pixel ein Bild generieren!
$iColor = DllStructGetData($tPixel, 1, $iRowOffset + $j) ;get pixel color
Local $iSave = $idFile_Album_rescale & $iFilelist[Random(1, $iFilelist[0], 1)]
if NOT _IsChecked($idCheckbox_SamePicture) Then
While StringInStr($iSave, "Thumbs.db") or ($iSave == $iSave_old)
Local $iSave = $idFile_Album_rescale & $iFilelist[Random(1, $iFilelist[0], 1)] ; Random(1,$iFilelist[0],1) ;Zufälligses Bild auswählen!
WEnd
Else
While StringInStr($iSave, "Thumbs.db")
Local $iSave = $idFile_Album_rescale & $iFilelist[Random(1, $iFilelist[0], 1)] ; Random(1,$iFilelist[0],1) ;Zufälligses Bild auswählen!
WEnd
EndIf
$iSave_old = $iSave
$bitmap_from_file = _GDIPlus_BitmapCreateFromFile($iSave) ; Grafik zwischenspeichern, die Bilddatei auf die enstprechende Position legen.
$iColorHEX = $iFrame_Transparenz & String(Hex($iColor, 6)) ;Farbe der transparenzen umrandung ermitteln
Local $hPen = _GDIPlus_PenCreate(($iColorHEX), $iFilter_Frame_width) ;color format AARRGGBB (hex)
$iSave2 = _GDIPlus_ImageGetGraphicsContext($bitmap_from_file)
_GDIPlus_GraphicsDrawRect($iSave2, 0, 0, GUICtrlRead($idwidth), GUICtrlRead($idwidth), $hPen)
$iColor_Brush = $iFilter_Transparenz & String(Hex($iColor, 6))
Local $hBrush = _GDIPlus_BrushCreateSolid($iColor_Brush) ;color format AARRGGBB (hex)
_GDIPlus_GraphicsFillRect($iSave2, 0, 0, GUICtrlRead($idwidth), GUICtrlRead($idwidth), $hBrush)
If _IsChecked($idRadio_Rotation) Then
_GDIPlus_ImageRotateFlip($bitmap_from_file, Random(0, 4, 1)) ; Randomfunktion mit einem 1D Array mit vorgegebenen Zahlen 0 und 4
EndIf
If _IsChecked($idRadio_Mirror) Then
_GDIPlus_ImageRotateFlip($bitmap_from_file, $aRandom[Random(0, 1, 1)]) ; Randomfunktion mit einem 1D Array mit vorgegebenen Zahlen 0 und 4
EndIf
_GDIPlus_GraphicsDrawImage($backbuffer, $bitmap_from_file, $j * $iImageWidth_Pixel_Pic, $i * $iImageHeight_Pixel_Pic) ; Kleine Grafik in die Bilddatei malen
_GDIPlus_BrushDispose($hBrush)
_GDIPlus_PenDispose($hPen)
_GDIPlus_ImageDispose($bitmap_from_file)
_GDIPlus_ImageDispose($iSave)
Next
$iPercent = Round($iCounter / ($iImageHeight * $iImageWidth) * 100, 0) ; % Anzeige Durchlauf/(Hoehe*Breite*100)
$iTime = Round(_Timer_Diff($hStarttime) / 1000, 0) ;Zeit in Sekunden angeben
$iRestzeit = Round($iTime / $iPercent * 100 - $iTime, 0) ; Restzeit
$iCounter = $iCounter + $iImageWidth ; Durchlauf um 1 Hochzählen! Sicher auch mit $i*$j oder so machbar
GUICtrlSetData($label_Progress, $iPercent & "%" & " " & $iTime & " Dauer Sekunden | geschätzte Restzeit = " & $iRestzeit)
GUICtrlSetData($idProgressbar1, Round($iCounter / ($iImageHeight * $iImageWidth) * 100, 0))
Next
_GDIPlus_BitmapUnlockBits($hImage, $tBitmapData) ;unlocks a portion of a bitmap that was locked by _GDIPlus_BitmapLockBits
$iFilename = @ScriptDir & "\Ausgabe\" & $iImageHeight & $iImageWidth & $iTime & " " & @HOUR & @MIN & @SEC & ".jpg"
_GDIPlus_ImageSaveToFile($bitmap, $iFilename)
_GDIPlus_BitmapDispose($bitmap) ;Bilddateien für Windows wieder freigeben!
_GDIPlus_GraphicsDispose($backbuffer) ;Bilddateien für Windows wieder freigeben!
_GDIPlus_Shutdown()
ShellExecute($iFilename) ;Bild oeffnen!
MsgBox(0, "PIC to PIC Generator", "Fertig Dauer: " & $iTime & " Sekunden")
EndFunc ;==>Bild_Zusammenbauen
Func DrawInsert($hGraphic, $hImage2, $iX, $iY, $fAngle, $iWidth, $iHeight, $iARGB = 0xFF000000, $iPenWidth = 1)
Local $hMatrix, $hPen2
$hMatrix = _GDIPlus_MatrixCreate()
_GDIPlus_MatrixRotate($hMatrix, $fAngle, "False")
_GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix)
_GDIPlus_GraphicsDrawImage($hGraphic, $hImage2, $iX, $iY)
$hPen2 = _GDIPlus_PenCreate($iARGB, $iPenWidth)
_GDIPlus_GraphicsDrawRect($hGraphic, $iX, $iY, $iWidth, $iHeight, $hPen2)
_GDIPlus_MatrixDispose($hMatrix)
_GDIPlus_PenDispose($hPen2)
Return 1
EndFunc ;==>DrawInsert
Func SelectFileVorlage()
Local $hGraphic
Local Const $sMessage = "Select a single file of any type."
Local $sFileOpenDialog = FileOpenDialog($sMessage, @ScriptDir & "\" & "Vorlage\", "Bild (*.png)", $FD_FILEMUSTEXIST)
If @error Then
; Display the error message.
MsgBox($MB_SYSTEMMODAL, "", "No file was selected.")
FileChangeDir(@ScriptDir)
Else
FileChangeDir(@ScriptDir)
$sFileOpenDialog = StringReplace($sFileOpenDialog, "|", @CRLF)
GUICtrlSetData($idFile, $sFileOpenDialog)
EndIf
_GDIPlus_Startup() ; Load PNG image
_WinAPI_RedrawWindow($hGUI)
Local $hImage = _GDIPlus_ImageLoadFromFile(GUICtrlRead($idFile))
Local $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI)
Local $iImageHeight = _GDIPlus_ImageGetHeight($hImage)
Local $iImageWidth = _GDIPlus_ImageGetWidth($hImage)
GUICtrlSetData($idLabel_Outputresolution,"Aufloesung der Ausgabe = " & $iImageWidth * GUICtrlRead($idwidth) & "X" & $iImageHeight * GUICtrlRead($idwidth))
_GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
EndFunc ;==>SelectFileVorlage
Func SelectFileAlbum()
Local Const $sMessage = "Select a folder"
Local $sFileSelectFolder = FileSelectFolder($sMessage, @ScriptDir & "\" & "Album 28.01.2017\")
If @error Then
MsgBox($MB_SYSTEMMODAL, "", "No folder was selected.")
Else
EndIf
EndFunc ;==>SelectFileAlbum
Func _PIC_scale($iAlbum_Folder)
Local $hBitmap1, $hImage1, $hGraphics
Local $width_resize = GUICtrlRead($idwidth)
Local $height_resize = GUICtrlRead($idwidth)
_GDIPlus_Startup()
DirCreate("Album rescale\")
$iFilelist_PIC = _FileListToArray($iAlbum_Folder, "*.jpg")
For $j = 1 To $iFilelist_PIC[0]
$hBitmap1 = $iAlbum_Folder & $iFilelist_PIC[$j]
;MsgBox(0, "TEST", $hBitmap1)
$hImage = _GDIPlus_BitmapCreateFromFile($hBitmap1)
$hImage_rescale = _GDIPlus_ImageResize($hImage, $width_resize, $height_resize)
$hGraphics = _GDIPlus_ImageGetGraphicsContext($hImage_rescale)
$sSave_mini_Image = @ScriptDir & "\Album rescale\" & $iFilelist_PIC[$j]
_GDIPlus_ImageSaveToFile($hImage_rescale, $sSave_mini_Image)
GUICtrlSetData($label_Progress,"Bild wird neu skaliert " & $sSave_mini_Image)
_GDIPlus_ImageDispose($hImage1)
_WinAPI_DeleteObject($hBitmap1)
If @error Then
ConsoleWrite("ERROR " & @error & @CRLF)
EndIf
Next
_GDIPlus_Shutdown()
;Return ("Album rescale\")
EndFunc ;==>_PIC_scale
Alles anzeigen
Unaufgeräumten Code hochgeladen.