You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PowerShell中调整动态GIF图片的尺寸?

PowerShell中基于.NET实现GIF动图缩放并保留透明度

已实现静态图片的缩放逻辑,但处理多帧GIF时仅能生成第一帧,需基于PowerShell默认.NET框架实现完整的GIF缩放,且保留透明度。以下是完整解决方案:

function Resize-Image {
    param (
        [System.Drawing.Image]$originalImage,
        [int]$newHeight,
        [int]$newWidth
    )

    # 处理GIF动图
    if ($originalImage.RawFormat.Guid -eq [System.Drawing.Imaging.ImageFormat]::Gif.Guid) {
        $dimension = $originalImage.FrameDimensionsList[0]
        $frameCount = $originalImage.GetFrameCount($dimension)
        
        # 获取GIF编码器
        $gifEncoder = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.FormatID -eq [System.Drawing.Imaging.ImageFormat]::Gif.Guid }
        if (-not $gifEncoder) {
            throw "无法找到GIF编码器"
        }

        # 创建编码器参数,用于保存帧属性(如延迟时间)
        $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1)
        $encoderParam = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Delay, 0)
        $encoderParams.Param[0] = $encoderParam

        # 创建内存流存储生成的GIF
        $memoryStream = New-Object System.IO.MemoryStream

        foreach ($frameIndex in 0..($frameCount - 1)) {
            # 选中当前帧
            [void]$originalImage.SelectActiveFrame($dimension, $frameIndex)
            
            # 创建带透明度的目标位图(ARGB32格式)
            $resizedFrame = New-Object System.Drawing.Bitmap($newWidth, $newHeight, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
            
            # 绘制缩放后的帧,保留透明度
            $graphics = [System.Drawing.Graphics]::FromImage($resizedFrame)
            $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
            $graphics.CompositingMode = [System.Drawing.Drawing2D.CompositingMode]::SourceOver
            $graphics.Clear([System.Drawing.Color]::Transparent)
            $graphics.DrawImage($originalImage, 0, 0, $newWidth, $newHeight)
            $graphics.Dispose()

            # 获取原帧的延迟时间(单位:1/100秒)
            $frameDelay = $originalImage.GetPropertyItem(0x5100)
            if ($frameDelay) {
                $delayValue = [System.BitConverter]::ToInt32($frameDelay.Value, 0)
                $encoderParam.Value = $delayValue
            }

            # 写入帧:第一帧用Save,后续用SaveAdd
            if ($frameIndex -eq 0) {
                $resizedFrame.Save($memoryStream, $gifEncoder, $encoderParams)
            }
            else {
                $resizedFrame.SaveAdd($encoderParams)
            }

            $resizedFrame.Dispose()
        }

        # 重置流位置并生成最终的Image对象
        $memoryStream.Position = 0
        $resizedImage = [System.Drawing.Image]::FromStream($memoryStream)
        # 注意:这里不能直接Dispose内存流,否则Image会失效;若需释放需等Image不再使用后处理
        return $resizedImage
    }
    # 处理静态图片
    else {
        # 创建带透明度的位图,保留原图属性
        $resizedImage = New-Object System.Drawing.Bitmap($newWidth, $newHeight, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
        $graphics = [System.Drawing.Graphics]::FromImage($resizedImage)
        $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
        $graphics.CompositingMode = [System.Drawing.Drawing2D.CompositingMode]::SourceOver
        $graphics.Clear([System.Drawing.Color]::Transparent)
        $graphics.DrawImage($originalImage, 0, 0, $newWidth, $newHeight)
        $graphics.Dispose()
        return $resizedImage
    }
}

关键实现细节

  • 多帧GIF存储:使用*MemoryStream*承载多帧数据,第一帧通过*Save*方法写入,后续帧用*SaveAdd*追加,确保GIF动画的完整性。
  • 透明度保留:创建目标位图时指定*Format32bppArgb*像素格式,绘制前调用Clear([System.Drawing.Color]::Transparent)清除画布,同时设置*CompositingMode*为SourceOver,保证透明通道正确渲染。
  • 动画属性继承:读取原帧的延迟时间属性(属性ID为0x5100),将其赋值给编码器参数,保留原GIF的播放节奏。
  • 资源管理:及时释放*Graphics*和临时Bitmap对象,避免内存泄漏;注意:返回Image对象后,关联的MemoryStream不能立即释放,否则Image会失效,需在Image不再使用后统一清理。

内容的提问来源于stack exchange,提问作者Tor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 05:27:49