Public/Export-XKCDTerminalImage.ps1
|
function Export-XKCDTerminalImage { <# .SYNOPSIS Renders a comic using the current terminal's inline image graphics protocol (Sixel, Kitty, or iTerm2) and saves the result to a file, so it can be redisplayed later with Import-XKCDTerminalImage. .DESCRIPTION The Export-XKCDTerminalImage cmdlet gets a comic and renders it exactly as Show-XKCD would -- using whichever inline graphics protocol your terminal supports -- but instead of writing the result to the console, it saves it to a file. That file can later be redisplayed instantly with Import-XKCDTerminalImage or Show-XKCD -Path, without needing network access or having to regenerate the image data again (which for Sixel in particular can take a while for large images). The saved file includes every field returned by Get-XKCD for the comic (num, title, alt, img, and so on), alongside the rendered image, so it can also be used as a self-contained, offline copy of the comic's full details. Because the saved file contains a protocol-specific escape sequence, it's only guaranteed to display correctly again in a terminal that supports the same graphics protocol it was exported with. The saved file records which protocol that was, and Import-XKCDTerminalImage and Show-XKCD -Path warn you if it doesn't match the protocol detected for the terminal you're importing it into. By default, Export-XKCDTerminalImage exports the latest available comic. When you use the -Num parameter you can specify one or more specific comics to export. .EXAMPLE Export-XKCDTerminalImage Exports the latest comic to the current working directory, e.g. as '.\2000.xkcdterm.json'. .EXAMPLE Export-XKCDTerminalImage -Num 353 -Path C:\XKCD Exports comic number 353 to C:\XKCD, as 'C:\XKCD\353.xkcdterm.json'. .EXAMPLE Get-XKCD -Newest 5 | Export-XKCDTerminalImage -Path C:\XKCD Exports the 5 most recent comics to C:\XKCD. .EXAMPLE Export-XKCDTerminalImage -Num 353 -PassThru | Import-XKCDTerminalImage Exports comic number 353 and immediately redisplays it from the saved file. .EXAMPLE Export-XKCDTerminalImage -Num 353 -Force Re-exports comic number 353, overwriting '.\353.xkcdterm.json' if it already exists. Without -Force, Export-XKCDTerminalImage throws rather than overwrite an existing file. .LINK https://xkcd.com/json.html #> [cmdletbinding(SupportsShouldProcess)] Param( # Exports the specified comics. Accepts array input. By default the latest comic is exported. [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] [int[]] $Num, # Renders the higher resolution (_2x) version of the image, where available. Comics that do not have a # higher resolution version are rendered at the standard quality instead. Defaults to the value saved # with Set-XKCDDefault -HighQuality, if any. [switch] $HighQuality = (Get-XKCDDefaultValue -Name 'HighQuality' -Value $false), # The local directory to save the exported file(s) to. Each comic is saved as '<num>.xkcdterm.json'. By # default this is the current working directory, unless a default has been saved with # Set-XKCDDefault -Path. [string] $Path = (Get-XKCDDefaultValue -Name 'Path' -Value $PWD), # Returns a FileInfo object for each file saved, e.g. so it can be piped directly into # Import-XKCDTerminalImage. [switch] $PassThru, # Overwrites the destination file if it already exists. Without -Force, Export-XKCDTerminalImage throws # rather than overwrite an existing export. [switch] $Force ) Begin { if (-not $Num) { $Num = (Invoke-RestMethod 'https://xkcd.com/info.0.json').num } } Process { $Num | ForEach-Object { $Comic = Get-XKCD -Num $_ $OutFile = Join-Path $Path "$($Comic.num).xkcdterm.json" if ((Test-Path $OutFile) -and -not $Force) { throw "A terminal image for comic #$($Comic.num) already exists at '$OutFile'. Use -Force to overwrite it." } $Extension = [System.IO.Path]::GetExtension(([uri]$Comic.img).AbsolutePath) $ImageUrl = $Comic.img if ($HighQuality) { $ImageUrl = $Comic.img.Insert($Comic.img.LastIndexOf($Extension), '_2x') } try { $ImageBytes = (Invoke-WebRequest $ImageUrl -UseBasicParsing -ErrorAction Stop).Content } catch { if ($HighQuality) { Write-Warning "High quality image not available for comic $($Comic.num), using standard quality instead" $ImageBytes = (Invoke-WebRequest $Comic.img -UseBasicParsing).Content } else { throw } } $Protocol = Get-XKCDTerminalGraphicsProtocol if (-not $Protocol) { Write-Warning "Your terminal does not appear to support inline image display (Sixel, Kitty, or iTerm2 graphics protocols), so comic #$($Comic.num) could not be exported." return } try { $TerminalImage = ConvertTo-XKCDTerminalImage -ImageBytes $ImageBytes -Protocol $Protocol } catch { Write-Warning "Unable to render comic #$($Comic.num) as $($Protocol): $_" return } if ($PSCmdlet.ShouldProcess($OutFile, "Save the $Protocol terminal image for comic #$($Comic.num)")) { $Comic | Add-Member -NotePropertyName Protocol -NotePropertyValue $Protocol -Force $Comic | Add-Member -NotePropertyName Image -NotePropertyValue $TerminalImage -Force $Comic | ConvertTo-Json | Out-File $OutFile -Force if ($PassThru) { Get-Item $OutFile } } } } } |