Skip to content

Instantly share code, notes, and snippets.

@arenagroove
Created April 22, 2025 04:42
Show Gist options
  • Select an option

  • Save arenagroove/cf7bc47acf4e78d0b3ca3858bf7f00e3 to your computer and use it in GitHub Desktop.

Select an option

Save arenagroove/cf7bc47acf4e78d0b3ca3858bf7f00e3 to your computer and use it in GitHub Desktop.
PowerShell script to generate responsive <picture> HTML tags from image thumbnails. Supports srcset, sizes (px-to-em conversion), optional wrappers, suffix-based grouping, and original fallback detection using ffprobe.

HTML Picture Tag Generator (PowerShell)

Scan a folder of images and thumbnails to automatically generate responsive <picture> HTML tags with srcset attributes.

It supports custom filename patterns (e.g., image-thumb-33-820x461.jpg), optional HTML wrappers, automatic conversion of pixel-based sizes to em, and accurate fallback <img> tags using real image dimensions via ffprobe.


Features

  • ✅ Generates full <picture> blocks with <source srcset> and <img>
  • ✅ Supports thumbnail naming with or without a suffix
  • ✅ Automatically converts px units to em in sizes=""
  • ✅ Uses real original image dimensions for the fallback <img> tag
  • ✅ Optional HTML wrapper around each block (<div>, comments, etc.)
  • ✅ Sorts and groups thumbnails automatically by base image name
  • ✅ Outputs clean, production-ready HTML into a single file

Requirements


Configuration

Set these variables at the top of the script to match your needs:

$baseUrl       = "https://assets.example.com/"
$suffix        = "thumb" # Or "" for no suffix
$sizesAttr     = '(max-width:768px) 90vw, 44vw'
$classAttr     = "fit-cover"
$altText       = "My image"
$useOriginalAsFallback = $true
$outputFile    = "generated-picture-tags.html"
# -------------------------------------------------------------------
# Responsive <picture> Tag Generator with Wrapper and px-to-em Conversion
# -------------------------------------------------------------------
# === CONFIGURATION ===
$baseUrl = "https://assets.example.com/"
$suffix = "" # e.g., "thumb", or "" for no suffix
$sizesAttr = '(max-width:768px) 90vw, 44vw' # px values will be auto-converted to em
$classAttr = "fit-cover middle-center"
$altText = "Image"
$useOriginalAsFallback = $true
$outputFile = "generated-picture-tags.html"
# === Optional wrapper around each picture block ===
$wrapPicture = $true
$wrapperStart = '<!-- Image Start -->' + "`n<div class=`"stack-container media-container`">"
$wrapperEnd = '</div>' + "`n<!-- Image End -->"
# ======================
# === Thumbnail Pattern Matching ===
$pattern = if ($suffix -ne "") {
"-$suffix-(\d+)x(\d+)\.(jpg|png|webp)$"
} else {
"-(\d+)x(\d+)\.(jpg|png|webp)$"
}
$thumbGroups = @{}
# === Group thumbnails by base name ===
Get-ChildItem -File | Where-Object { $_.Name -match $pattern } | ForEach-Object {
$matches = [regex]::Match($_.Name, $pattern)
if ($matches.Success) {
$width = [int]$matches.Groups[1].Value
$height = [int]$matches.Groups[2].Value
$format = $matches.Groups[3].Value
$base = if ($suffix -ne "") {
$_.BaseName -replace "-$suffix-\d+x\d+$", ""
} else {
$_.BaseName -replace "-\d+x\d+$", ""
}
if (-not $thumbGroups.ContainsKey($base)) {
$thumbGroups[$base] = @()
}
$thumbGroups[$base] += [PSCustomObject]@{
File = $_.Name
Width = $width
Height = $height
Format = $format
}
}
}
# === HTML Generation ===
$htmlBlocks = @()
foreach ($baseName in $thumbGroups.Keys) {
$thumbs = $thumbGroups[$baseName] | Sort-Object Width
$srcset = ($thumbs | ForEach-Object {
"$baseUrl$($_.File) $($_.Width)w"
}) -join ",`n "
# === Determine fallback image and dimensions ===
if ($useOriginalAsFallback) {
$originalFile = Get-ChildItem -File | Where-Object {
$_.BaseName -eq $baseName -and $_.Extension -match "\.(jpg|png|webp)$"
} | Select-Object -First 1
if ($null -ne $originalFile) {
$fallbackSrc = "${baseUrl}$($originalFile.Name)"
try {
$owidth = ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=p=0 "`"$($originalFile.FullName)`""
$oheight = ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 "`"$($originalFile.FullName)`""
$fallbackWidth = [int]$owidth
$fallbackHeight = [int]$oheight
} catch {
Write-Output "⚠️ Could not get dimensions for $($originalFile.Name), using 1024x576 fallback."
$fallbackWidth = 1024
$fallbackHeight = 576
}
} else {
Write-Output "⚠️ Original file not found for $baseName"
$fallbackSrc = "${baseUrl}${baseName}.jpg"
$fallbackWidth = 1024
$fallbackHeight = 576
}
} else {
$largest = $thumbs[-1]
$fallbackSrc = "$baseUrl$($largest.File)"
$fallbackWidth = $largest.Width
$fallbackHeight = $largest.Height
}
# === Convert px to em in sizesAttr using [regex]::Replace
$sizesProcessed = [regex]::Replace($sizesAttr, "(\d+)px", {
param($match)
$px = [int]$match.Groups[1].Value
"{0:0.###}em" -f ($px / 16)
})
# === Build <picture> block
$pictureBlock = @"
<picture>
<source
srcset="
$srcset"
sizes="$sizesProcessed">
<img
class="$classAttr"
src="$fallbackSrc"
width="$fallbackWidth"
height="$fallbackHeight"
alt="$altText"
decoding="async">
</picture>
"@.Trim()
$block = if ($wrapPicture) {
"$wrapperStart`n$pictureBlock`n$wrapperEnd"
} else {
$pictureBlock
}
$htmlBlocks += $block
}
# === Output final HTML ===
$htmlOutput = $htmlBlocks -join "`n`n"
Set-Content -Path $outputFile -Value $htmlOutput -Encoding UTF8
Write-Output "`n✅ Picture tags written to '$outputFile'"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment