Bild mit Powershell automatisch skalieren?

2 Antworten

Ich habe keine Ahnung wo Du das Script aufgesammelt hast...

Ohne die Fehlermeldungen zu kennen kann ich nicht mal Ahnen wo der Fehler liegt.

Warum verwendest Du eine 3.Anbieter.dll? Windows hat alles Nötige gut dokumentiert an Bord. (und das Netz ist voll von Diversen C# und PowershellScripts zu diesem Thema)

ich setze noch eines hinzu:

#hier  solltest Du  nur  rumfummeln,  wenn Du weißt was Du tust...
function Resize-Image
  {
    <#
    .EXAMPLE
      Resize-Image -InputFile "C:\kitten.jpg" -OutputFile "C:\kitten2.jpg" -TargetSize 300 -Quality 100]
      Resized die Größte Ausdehnung auf 300 , speichert mit 100% Jpeg-Qualität
    #>
  
    Param(
      [Parameter(ValueFromPipeline=$true,Mandatory=$true)][string]$InputFile, 
      [Parameter(Mandatory=$true)][string]$OutputFile, 
    [Parameter(Mandatory=$true)][int][ValidateRange(1, [int]::MaxValue)]$TargetSize,
    [parameter(Mandatory=$false)][int][ValidateRange(1, 100)]$Quality=80
  )

  Add-Type -AssemblyName System.Drawing

  try{
    $img = [System.Drawing.Image]::FromFile((Get-Item $InputFile))
  }
  catch{return} # habe keine Lust auf großartige Fehlerbehandlung, wenn die Quelldatei mal kein Bild ist... einfach wieder zurück zum Aufrufer

  $ratioX = $TargetSize / $img.Width
  $ratioY = $TargetSize / $img.Height
  $ratio = $ratioY
  if ($ratioX -le $ratioY) {
    $ratio = $ratioX
  }
  [int32]$new_width = $img.Width * $ratio
  [int32]$new_height = $img.Height * $ratio

  $newImg = New-Object System.Drawing.Bitmap($new_width, $new_height)

  # Zeichne Bild in ein leeres Canvas
  $graph = [System.Drawing.Graphics]::FromImage($newImg)
  $graph.InterpolationMode = 'HighQualityBicubic'
  $graph.DrawImage($img, 0, 0, $new_width, $new_height)
   
  #ermittle Codecinfomationen des Originalbildes und setze (Jpeg)Qualität ..für PNG etc. irrelevant
  $Codec=[System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|?{$img.RawFormat -match $_.FormatID}
  $encoderParams=New-Object System.Drawing.Imaging.EncoderParameters(1) 
  $encoderParams.Param[0]=New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality,$Quality) 
   
  $newImg.Save($OutputFile, $Codec, $encoderParams)
   
  $graph.Dispose()
  $img.Dispose()
  $newImg.Dispose()
}

#=============== Hier gehts los =========================#
$ZielGroesse=500
$ZielQualitaet=70
$Zielordner=New-Item -Path "$Env:UserProfile\Desktop" -Name "ResizedImages" -ItemType "directory" -Force
 # Auch wenn Resize-Image mit Dateien zurechtkommt welche keine Bilder sind, trotzdem auf gewünschte Formate filtern
Get-ChildItem -Path .\* -file -Include '*.jpg', '*.png', '*.gif'|
  ForEach-Object{
    $ZielDatei='{0}\{1}'-f $Zielordner.FullName,$_.Name
    $QuellDatei=$_.FullName
    Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -TargetSize $ZielGroesse -Quality $ZielQualitaet
  }
'Fretig'
pause1
Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
Powershellnoob 
Fragesteller
 13.10.2022, 01:37

Hallo Erzesel, ich möchte alle Bilder in einer Datei auf die Größe 470x255 skalieren. Cool das Windows, das auch kann. Ich bin bei meinen Recherchen auf einen Youtube-Kanal mit dem Namen german Powershell aufmerksam geworden. Bei ihm, dass das Skript von mir ohne Probleme funktioniert. Allerdings ist es sehr cool, dass ohne eine 3 Hersteller .dll funktioniert.

Ich hätte allerdings noch 2 Fragen.

Wo muss ich hier den Zielordner angeben.

Wie kann ich die Pixel Anzahl von 470x255 erreichen?

Vielen Dank schon mal im Voraus.

0

Ich habe die Antwort auf Deine Kommentar mal Hoch genommen:

Wo muss ich hier den Zielordner angeben.

Habe mal die Passage für die Angabe des ZielOrdners umgestaltet:

ab Zeile 113

...
#=============== Hier gehts los =========================#
  #Hier den pfad  für deinen Zielordner angeben
$Zielordner='c:\irgendwo\DeinOrdner'
...
Wie kann ich die Pixel Anzahl von 470x255 erreichen?

Das hatte ich im ersten Script garnicht erst erwogen, da es eigentlich bei vollautomatischen Sachen üblich ist das Seitenverhältnis des Originals zu übernehmen. Ich habe den Code entsprechen angepasst nun kannst Du Breite und Höhe in der Aufrufzeile des Cmdlet Resize-Image angeben:

Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255 

In der einfachsten Variante gibt's jedoch, je nach Vorlage, mehr oder wenige sichtbare hässliche Verzerrungen...

Bild zum Beitrag

Bild zum Beitrag

Um das zu vermeiden benötigen feste Bildgrößen eine Letterbox/Pillarbox in welcher das Bild im richtigen Seitenverhältnis dargestellt wird:

Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255  -Quality 75 -KeepAspectRatio 

Bild zum Beitrag

Bild zum Beitrag

und weil ich einmal am Basteln war kannst Du auch noch die Grundfarbe festlegen...

Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255 -AR -BackgroundColor '#80ff40'

Bild zum Beitrag

Bild zum Beitrag

resize.ps1

function Resize-Image
  {
    <#
    
    .PARAMETER -InputFile  Type [string]
      Original Datei voller Pfad  nötig!
    .PARAMETER -OutputFile Type [string]
      Ausgabedatei
    .PARAMETER -Width Type [int] >0 Alias -Size
      Bildbreite  bzw  gröste Ausdehnung,  wenn keine Breite  angegeben
    .PARAMETER -Height Type [int] >=0  optional
      Wenn 0 oder  nicht angegebe, wird  auf größte Ausdenung vergrößert
    .PARAMETER -Quality Type [int] 1..100 optional
      Gibt  für Jpeg aufgabe die Quallität an
    .PARAMETER -KeepAspectRatio Switch optional  Alias -AR 
      Wenn Höhe und Breite  angegeben sind, wird  unter Beibehaltung des Seitenvehältnisses in eine Letter-/PillarBox gezeichnet
    .PARAMETER -BackgroundColor Type [string] optional  Alias -BC
      Gibt die Farbe für die Bildbox an  (HTML-HexFormat #ffffff oder internationaler Farbname) https://en.wikipedia.org/wiki/Web_colors#Extended_colors

    .EXAMPLE
      -Resize die größte Ausdehnung auf 300 , speichert mit 100% Jpeg-Qualität
      Resize-Image -InputFile "C:\kitten.jpg" -OutputFile "C:\kitten2.jpg" -Size 300 -Quality 100
      -Resize auf 800x600 80% Jpeg-Qualität (Bild  wird  evtl. verzerrt)
      Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 800 -Height 600
      -dito  ...Aspektratio erhalten, in Box zeichnen
      Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 800 -Height 600  -Quality 75 -KeepAspectRatio 
      -dito mit farbiger Box  (HTML-HexFormat #ffffff oder internationaler Farbname)
      Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 300 -Height 800  -Quality 100 -AR -BackgroundColor '#80ff40'
      
    #>
  
    Param(
      [Parameter(ValueFromPipeline=$true,Mandatory=$true)][string]$InputFile, 
      [Parameter(Mandatory=$true)][string]$OutputFile, 
      [Parameter(Mandatory=$true)][ValidateRange(1, [int]::MaxValue)]
        [Alias('Size')][int]$Width,
      [Parameter(Mandatory=$false)][int][ValidateRange(1, [int]::MaxValue)]$Height = 0,
      [Parameter(Mandatory=$false)][int][ValidateRange(1, 100)]$Quality=80,
      [Parameter(Mandatory=$false)][Alias('AR,KAR')][Switch]$KeepAspectRatio = $false,
      [Parameter(Mandatory=$false)][Switch]$Crop = $false,
      [Parameter(Mandatory=$false)][Alias('BC')][string]$BackgroundColor = '#000000'
    )

  Add-Type -AssemblyName System.Drawing

  try{
    $image = [System.Drawing.Image]::FromFile((Get-Item $InputFile))
  }
  catch{return} # habe keine Lust auf großartige Fehlerbehandlung, wenn die Quelldatei mal kein Bild ist... einfach wieder zurück zum Aufrufer

   #Grundeinstellungen für die Zeichenfläche
  $canvasDrawPosX = 0
  $canvasDrawPosY = 0
  $canvasWidth = $Width
  $canvasHeight = $Height

  if (!$Height){
      $Height = $Width
       # resize auf die größte Ausdehnung behalte Aspektratio
      $ratioX = $Width / $image.Width
      $ratioY = $Height / $image.Height
      $ratio = [Math]::Min($ratioY,$ratioX) #Resize die gößere Ausdehnug ...Min() gibt die kleinere Ratio zurück
      [int]$drawWidth = $image.Width * $ratio
      [int]$drawHeight = $image.Height * $ratio
      $canvasWidth = $drawWidth
      $canvasHeight = $drawHeight
    }
    elseif ($KeepAspectRatio){
       # zeichne in eine Box
      $ratioX = $canvasWidth / $image.Width
      $ratioY = $canvasHeight / $image.Height
      $ratio = [Math]::Min($ratioY,$ratioX)
      $drawWidth = [Math]::Ceiling($image.Width * $ratio)
      $drawHeight = [Math]::Ceiling($image.Height * $ratio)
       #Zeichenpositionen  berechnen
      if ($ratioY -lt $ratioX){
        $canvasDrawPosX = [Math]::Floor(($canvasWidth - $drawWidth) / 2)    # für Pilarbox
      }
      else{
        $canvasDrawPosY= [Math]::Floor(($canvasHeight - $drawHeight) / 2)  # für Letterbox
      }
    }
   else{
       #egal... dann kanns eben verzerrt  werden
      $drawWidth = $canvasWidth
      $drawHeight = $canvasHeight
   }

  #erzeuge Zeichenfläche
  $canvas = New-Object System.Drawing.Bitmap($canvasWidth, $canvasHeight)

  $graph = [System.Drawing.Graphics]::FromImage($canvas)
  $graph.InterpolationMode = 'HighQualityBicubic'
  try{ $graph.Clear($BackgroundColor) }catch{} #fehlerhafte Farbangabe abfangen (bei Fehler bleibts  Schwarz)
  
  # Zeichne Bild in ein leeres Canvas
  $graph.DrawImage($image, $canvasDrawPosX , $canvasDrawPosY, $drawWidth, $drawHeight)

  #ermittle Codecinfomationen des Originalbildes und setze (Jpeg)Qualität ..für PNG etc. irrelevant
  $Codec=[System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|?{$image.RawFormat -match $_.FormatID}
  $encoderParams=New-Object System.Drawing.Imaging.EncoderParameters(1) 
  $encoderParams.Param[0]=New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality,$Quality) 
   
  $canvas.Save($OutputFile, $Codec, $encoderParams)
   
  $graph.Dispose()
  $image.Dispose()
  $canvas.Dispose()
}

#=============== Hier gehts los =========================#
  #Hier den pfad  für deinen Zielordner angeben
$Zielordner='c:\irgendwo\DeinOrdner'

$Zielordner=New-Item -Path $Zielordner -ItemType "directory" -Force
 # Auch wenn Resize-Image mit Dateien zurechtkommt welche keine Bilder sind, trotzdem auf gewünschte Formate filtern
Get-ChildItem -Path .\* -file -Include '*.jpg', '*.png', '*.gif'|
  ForEach-Object{
    $ZielDatei='{0}\{1}'-f $Zielordner.FullName,$_.Name
    $QuellDatei=$_.FullName
    
      #hier mal ein Paar  vorgefertigte Aufruf-Beispiele zum Exprimentieren.
      #Einfach vor der gewünschten Zeile das Kommentarzeichen # entfernen  setzen:
    #Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Size  470  -Quality 100 
    #Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255  -Quality 75 -KeepAspectRatio 
    #Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255  -Quality 100 -AR -BackgroundColor 'MidnightBlue'
    Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255 -AR -BackgroundColor '#80ff40'
    #Resize-Image -InputFile $QuellDatei -OutputFile $ZielDatei -Width 470 -Height 255 
  }
'Fertig'
pause

Ich habe Dir zum experimentieren einige Aufrufzeilen vorbereitet.

Ab der mit :

#=============== Hier gehts los =========================#

... gekennzeichneten Stelle kannst Du nach Herzenslust herumspielen ohne besonders viel kaputt zu machen

hier noch eine Farbtabelle mit den internationalen Farbnamen

Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
 - (PowerShell, Powershell ISE)  - (PowerShell, Powershell ISE)  - (PowerShell, Powershell ISE)  - (PowerShell, Powershell ISE)  - (PowerShell, Powershell ISE)  - (PowerShell, Powershell ISE)