en-US/about_PSImageConverter.help.txt

TOPIC
    about_PSImageConverter

SHORT DESCRIPTION
    Cross-platform image conversion (HEIC/HEIF and more), powered by Magick.NET.

LONG DESCRIPTION
    PSImageConverter converts images, for example HEIC/HEIF photos taken with
    an iPhone, to JPEG, PNG, WebP, AVIF, JPEG XL, TIFF, BMP or GIF and reads
    their metadata. The Magick.NET library and its native ImageMagick build are
    bundled with the module, so no codecs need to be installed. It requires
    PowerShell 7.4 or later and runs on Windows, Linux and macOS (x64 and
    arm64; on Alpine/musl Linux x64 only).

    Cmdlets:

        Convert-Image Converts every format Magick.NET can read to the
                          -Format Jpeg, Png, WebP, Avif, Jxl (JPEG XL), Tiff,
                          Bmp or Gif.
        ConvertTo-Jpeg Convert-Image -Format Jpeg.
        ConvertTo-Png Convert-Image -Format Png (lossless, no -Quality).
        ConvertTo-WebP Convert-Image -Format WebP.
        ConvertTo-Avif Convert-Image -Format Avif.
        ConvertTo-JpegXL Convert-Image -Format Jxl.
        ConvertFrom-Heic Converts .heic/.heif/.hif files only; -Format
                          defaults to Jpeg.
        Get-ImageInfo Returns the format, dimensions, orientation, camera
                          and date taken of images; its objects can be piped
                          into the conversion cmdlets.

    The conversion cmdlets take -Path (wildcards) or -LiteralPath (aliases
    PSPath and LP; files piped from Get-ChildItem and the objects of
    Get-ImageInfo bind here; folders are skipped), -DestinationPath, -Quality
    (1 to 100, default 90, for Jpeg, WebP, Avif and Jxl), -StripMetadata,
    -Force, -WhatIf and -Confirm, and return a FileInfo object for every
    written file, the same object Get-Item returns, so it can be piped into
    the next cmdlet. The output gets the base name of the source and the
    extension of the format (.jpg, .png, .webp, .avif, .jxl, .tif, .bmp,
    .gif). A file given more than once in a call (e.g. by the patterns *.heic
    and IMG_*) is converted or described once. A conversion never overwrites
    its source file or a file written earlier in the same call, also not when
    the folder is reached through another path (a junction, a symbolic link,
    a subst or mapped drive, a UNC path), and never leaves a truncated or
    temporary file behind, also not when it is stopped with Ctrl+C.

    Wildcards skip hidden files and folders (on Windows those with the Hidden
    attribute, on Linux and macOS names that start with a dot), as
    Get-ChildItem does without -Force; -LiteralPath and a folder name without
    wildcards reach them.

METADATA
    The EXIF orientation is applied to the pixels, so the output is upright.
    Without -StripMetadata the output keeps the metadata its format can carry:

        Jpeg, Png EXIF, XMP, IPTC, ICC colour profile, comments
        WebP, Avif EXIF, XMP, ICC colour profile
        Jxl EXIF, XMP; ICC colour profile only at -Quality 100
        Tiff XMP, IPTC, ICC colour profile, comments
        Gif IPTC, ICC colour profile (browsers ignore it in
                          GIF files), comments
        Bmp ICC colour profile

    Tiff, Gif and Bmp output gets no EXIF data (date taken, camera, GPS
    location); a warning is written for every source with EXIF data unless
    -StripMetadata is used.
    -StripMetadata removes EXIF (including the GPS location), XMP, IPTC and
    comments but keeps the ICC colour profile.

    The colours are kept when the source carries an ICC profile, as iPhone
    photos do. A HEIC or AVIF source that signals its colours only through
    nclx/CICP (no ICC profile) with primaries other than sRGB/BT.709 (e.g.
    Display P3 or BT.2020, also HDR with PQ or HLG) is converted without
    colour conversion, so its colours look less saturated; Avif output keeps
    the CICP values.

    Lossy Jxl output (-Quality below 100) is always sRGB, because the bundled
    JPEG XL encoder stores an ICC colour profile only in lossless files. The
    pixels of a source with an ICC profile (e.g. Display P3 or Adobe RGB) are
    converted to sRGB first, so the photo looks the same; colours outside sRGB
    are clipped. Use -Quality 100 or Avif to keep a wide gamut. A grey profile
    in a colour image, which viewers ignore, is ignored here as well. Chrome
    shows a lossless Jxl file whose profile describes its tone curve as a
    table (e.g. Photoshop's 'Dot Gain 20%' grey profiles) without colour
    management; Firefox applies such a profile.

    Bytes after the size the header of an ICC profile declares are not part
    of the profile (Samsung Galaxy HEIC photos, for example, have two zero
    bytes there, and so do JPEGs converted from them). The profile is written
    without them in every output format, with unchanged colours (-Verbose
    says so). The Png encoder refuses a profile with such bytes.

    An ICC profile that the colour engine cannot apply, because it is damaged
    (e.g. cut short inside its tag data) or names an unknown colour space, is
    left out of every output (-Verbose says so): viewers ignore it in the
    source, Png and lossless Jxl output could not be written with it, and
    Chrome and Edge would not display an Avif that carries it. A profile that
    the colour engine can apply but the Png or lossless Jxl encoder cannot
    write (e.g. a version 4 profile whose length is not a multiple of 4, a
    header that declares a few more bytes than the profile has although all
    its tags are complete, or, for Jxl, a rendering intent above 3) is left
    out of that output only, so the file is still written (-Verbose says so).

    Grey images with a grey ICC profile (e.g. Photoshop's 'Dot Gain 20%' or
    'Gray Gamma 1.8', scanned greyscale) keep their grey pixels and the
    profile in Jpeg, Png, Tiff and lossless Jxl output. WebP, Avif, Bmp and
    Gif store grey pixels as RGB, for which a grey profile is not valid, so
    the pixels are converted to sRGB first. This includes a grey JPEG XL with
    a grey profile, which ImageMagick reads as RGB.

    A profile made for other pixels is not valid: viewers ignore a grey
    profile in a colour image, and browsers apply an RGB profile to the
    pixels of a grey JPEG, while Windows (Photos, Explorer) rejects it. Such
    a profile is kept, except where the file could not be written or would
    look different with it: it is left out of lossless Jxl output and, as a
    grey profile on colour pixels, out of Avif and Bmp output, and out of
    Jpeg, Png and Tiff output when the colour pixels are all neutral grey
    (these formats store them as grey). Neutral grey pixels with an RGB
    profile (a black-and-white photo in Adobe RGB) are stored as RGB in Jpeg,
    Png and Tiff output, so the profile stays valid.

    When the orientation is applied, an EXIF thumbnail is removed (it would
    show rotated against the photo), and the XMP orientation and pixel
    dimensions are updated.

    CMYK images (e.g. print JPEGs) stay CMYK with their colour profile in Jpeg
    and Tiff output; for the other formats they are converted to sRGB through
    their CMYK profile.

    Jpeg has no transparency: transparent and half-transparent pixels are
    placed on a white background (paper white for a CMYK image). The other
    formats keep the alpha channel (Gif only fully transparent or opaque
    pixels).

FRAMES AND DAMAGED FILES
    Only the first frame of an animated GIF or WebP, a multi-page TIFF or a
    HEIC file with several images is converted. A warning is written for every
    such source: 'Only the first of <N> frames is converted: <path>'.

    A source that ImageMagick can read but reports as damaged, e.g. a JPEG cut
    off by an interrupted copy (the missing part becomes grey) or an animated
    GIF cut off after its first frame (its frames cannot be counted then), is
    converted with the warning 'The image may be damaged (<reasons>): <path>';
    Get-ImageInfo writes the same warning. A JPEG that lacks only its end
    marker gets this warning as well, although its pixels are complete: the
    decoder reports it like a file that is cut off. Other ImageMagick
    warnings about a source go to the verbose stream.

    Writing HEIC files is not supported yet, because the bundled ImageMagick
    build does not contain an HEVC encoder. AVIF is the closest alternative.

ERRORS
    Errors about a file are non-terminating: the cmdlets continue with the
    next file, $? is $false afterwards, -ErrorVariable holds one record per
    failed file and -ErrorAction Stop stops at the first one. Every error has
    a stable id:

        PathNotFound the input matches no file; for a pattern the
                                message names a drive or folder that does not
                                exist, a folder part that is a file, a folder
                                part with wildcards that no folder (or only a
                                hidden one) matches, or, when the folder
                                exists, adds that wildcards skip hidden files
                                and that [ and ] are wildcard characters and
                                how to match them; for a PSDrive that is not
                                global it names the drive (see PSDRIVES)
        InvalidWildcardPattern -Path is not a valid pattern ('a[.jpg'); use
                                -LiteralPath
        UnsupportedProvider the input is not a file system path (one error
                                per input, also for a pattern)
        NotHeicFile ConvertFrom-Heic: no .heic/.heif/.hif file
        TargetIsSource the output would overwrite the source
        DuplicateTarget two sources of one call map to one output
        TargetExists the output exists and -Force is not set
        ConfirmationFailed -Confirm (or the caller's $ConfirmPreference)
                                asks for a confirmation the host cannot show,
                                e.g. in pwsh -NonInteractive; use
                                -Confirm:$false
        ImageReadFailed the source cannot be read
        ImageWriteFailed the output cannot be written, or the
                                destination folder cannot be created or
                                written to

    The target object is the source file; for PathNotFound,
    InvalidWildcardPattern and UnsupportedProvider it is the input as given.

    A -DestinationPath that cannot name a folder is a parameter error: it
    stops the whole call with one terminating error before any file is read,
    also with -WhatIf, and try/catch catches it without -ErrorAction Stop. Use
    $_ in the catch block or $Error[0] for the error record: -ErrorVariable
    holds the exception for these errors (its ErrorRecord property has the
    record). The ids are InvalidDestinationPath (white space only, an unknown
    drive or provider, invalid characters, on Windows also a colon after the
    drive such as C:\x:y, a drive-qualified path that climbs above the root of
    its drive such as Temp:\..\x, a PSDrive that is not global, see
    PSDRIVES), UnsupportedProvider (not a file system path) and
    DestinationNotDirectory (the path or one of its parent folders is a file,
    a junction or symbolic link whose target does not exist, or a link that
    cannot be resolved, such as one that points to itself); the target object
    is the -DestinationPath value. A relative path that climbs above
    the root of its drive stays at the root, as in other cmdlets. A folder
    that does not exist yet is created when the first file is written; when
    that fails (no permission, a read-only file system) or the folder cannot
    be written to, each file gets ImageWriteFailed.

    ConvertFrom-Heic and the ConvertTo-* cmdlets pass all files of one call to
    a single Convert-Image, so the errors it finds have the
    FullyQualifiedErrorId '<Id>,Convert-Image'. The checks they make before
    carry their own name: the -DestinationPath errors of every one of them,
    and the input errors (PathNotFound, InvalidWildcardPattern,
    UnsupportedProvider, NotHeicFile) of ConvertFrom-Heic. With
    Import-Module -Prefix, the errors raised inside Convert-Image during such
    a call keep the module's unprefixed name ',Convert-Image', while a direct
    call of the prefixed cmdlet and the checks of a prefixed wrapper carry
    the prefixed name.

    Separate calls or processes that write the same output file at the same
    time without -Force are not coordinated: on Windows the later one fails
    with TargetExists or ImageWriteFailed; on Linux and macOS both can succeed
    and the later file replaces the earlier one. With -Force the later file
    replaces the earlier one on every platform. Give parallel conversions
    different destination folders.

PREFERENCE VARIABLES
    Like compiled cmdlets, the cmdlets follow the preference variables of
    their caller ($WhatIfPreference, $ConfirmPreference,
    $ErrorActionPreference, $WarningPreference, $InformationPreference,
    $VerbosePreference, $DebugPreference), also when a script or function
    sets them in its own scope. Functions of a script module do not see such
    values by themselves (PowerShell issue #4568), so each cmdlet copies them
    when it starts. A function with SupportsShouldProcess that is called with
    -WhatIf therefore passes it on, and $ErrorActionPreference = 'Stop' in a
    script makes the first error terminating. A common parameter given to the
    cmdlet itself (-WhatIf, -Confirm, -ErrorAction, -WarningAction,
    -InformationAction, -Verbose, -Debug) wins.

PSDRIVES
    PSDrives that are not global cannot be used. A script module resolves
    paths in its own session state, which sees only the global drives; this
    is a limitation of the PowerShell engine (Microsoft.PowerShell.Archive
    behaves the same). A drive created with New-PSDrive without -Scope Global
    inside a function (also by a script dot-sourced there), at the top of a
    script run by its path or with & (.\setup.ps1, & .\setup.ps1), or in
    another module therefore fails in -Path and -LiteralPath with
    PathNotFound and in -DestinationPath with InvalidDestinationPath, and so
    does a relative input path while the current location is on such a
    drive. The message names the drive and its root. Create the drive with
    New-PSDrive -Scope Global, or use the file system path. A drive created
    at the prompt, in the profile, at the top level of pwsh -File or by a
    script dot-sourced there (. .\setup.ps1) is global and works.

    When such a drive has the name of a global drive (e.g. a script's own
    Temp:), the module would read and write on the global drive instead, so
    it fails the same way and the message names both roots. For a drive of
    another provider the message says that only file system paths are
    supported. Files piped from Get-ChildItem or Get-Item on such a drive
    work, because their PSPath holds the file system path, and so does a
    relative -DestinationPath; strings and the output of Resolve-Path (which
    has no PSPath) do not.

EXAMPLES
    PS C:\> ConvertFrom-Heic -Path .\IMG_1234.HEIC

    PS C:\> Get-ChildItem -Path C:\Pictures -Filter *.heic | ConvertFrom-Heic -Format Png

    PS C:\> Get-ChildItem -Path C:\Pictures -Filter *.jpg | ConvertTo-WebP -Quality 80 -DestinationPath C:\Pictures\web

    PS C:\> ConvertTo-Avif -Path .\IMG_1234.HEIC -StripMetadata

    PS C:\> Convert-Image -Path C:\Pictures\*.png -Format Tiff -WhatIf

    PS C:\> Get-ChildItem -Path C:\Pictures -Filter *.heic | Get-ImageInfo

    PS C:\> Get-ImageInfo -Path .\*.heic | Where-Object -Property Width -GT 4000 | ConvertTo-Jpeg

NOTE:
    Thank you to all those who contributed to this module, by writing code,
    sharing opinions, and provided feedback.

TROUBLESHOOTING NOTE:
    Look out on the GitHub repository for issues and new releases:
    https://github.com/fasteiner/PSImageConverter

SEE ALSO
    - Get-Help Convert-Image -Full
    - https://github.com/dlemstra/Magick.NET

KEYWORDS
    HEIC, HEIF, Image, Conversion, JPEG, PNG, WebP, AVIF, JpegXL, ImageMagick