如何在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
相关产品推荐
相关产品推荐

