Как я могу использовать анимированный PNG в UWP?

#c# #vb.net #xaml #uwp

#c# #vb.net #xaml #uwp

Вопрос:

У меня есть этот анимированный png из этого API, и я хочу поместить его на чью-то фотографию профиля, но она отображается только как фотография в 1 кадре.

Я хочу, чтобы был BitmapDecoder, но я не знаю, как настроить его в XAML.

введите описание изображения здесь

Кто-нибудь может мне помочь, пожалуйста?

Я уже пробовал это и выдает мне замороженный img:

 <Image   Source="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/items/1263950/ebe6b674deca163b28423e3b925bd36b0f0f357b.png" />
 

и это дает мне плохое черно-белое изображение :

 <BitmapIcon   UriSource="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/items/1263950/ebe6b674deca163b28423e3b925bd36b0f0f357b.png" />
 

Комментарии:

1. В UWP нет API для поддержки анимированного изображения PNG. Мы предлагаем вам использовать GIF-изображение в качестве анимированного iamge . Вы можете получить более подробную информацию об анимированном изображении GIF, обратившись к образцу .

2. @YanGu-MSFT проблема в том, что ответы API — это только png, поэтому, когда я конвертирую img в gif в любом месте, я получаю изображение с плохим размытием.

3. Я действительно ценю, что вы нашли время поделиться своими мыслями. Однако на данный момент нет поддержки API для анимации анимированного изображения png, предоставляемого вашим веб-сайтом.

Ответ №1:

Когда я опубликовал это, я только что заметил, что это старый пост, но, возможно, кто-то воспользуется им в будущем.

На самом деле, есть кое-что, с чем вы можете работать:

Извините, я только что заметил, что это вопрос UWP, не уверен, как WPF переводится в UWP, но мой ответ работает в WPF, но вы можете использовать класс box и просто нужно изменить конвертер.

Я изменил эту библиотеку https://github.com/murrple-1/APNGManagement и это работает.

Он был написан на C # и нацелен на winforms .NET framework 4.xx что-то. Но я использовал его в VB.NET и на .NET5.0 без проблем.

Что я сделал, так это клонировал репозиторий и добавил ссылку APNGLib на мой проект (the .dll-файл, который вы получаете при компиляции / сборке).

Затем создал usercontrol (WPF) для хранения изображения:

XAML

 <UserControl x:Class="ApngImg"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ToolSet"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Image x:Name="APNGcontrolIMG" Width="200" Height="200"/>
    </Grid>
</UserControl>
 

в коде, лежащем в основе xaml:

 
Imports System.IO
Imports APNGLib

Public Class ApngImg

    
    Sub New()
        DataContext = Me
        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Dim pngFilePath As String = "C:ebe6b674deca163b28423e3b925bd36b0f0f357b.png"
        Dim png As New APNG 'picturebox
        Using s As Stream = File.OpenRead(pngFilePath)
            png.Load(s)
        End Using
        Dim boxy As New APNGBox(png, APNGcontrolIMG)

    End Sub
 

Затем отредактировал оригинал APNGViewer_WinForms . APNGBox (переведено с C # на VB.NET )

Все, что я сделал, это добавил container as System.Windows.Controls.Image в конструктор, добавил частное свойство для контейнера и добавил функцию, которая преобразует System.Drawing.Bitmap в System.Windows.Media.Imaging.BitmapImage , чтобы изображение можно было отображать в элементе управления изображениями wpf.

     Public Function Convert(ByVal src As Bitmap) As BitmapImage
        Dim ms As MemoryStream = New MemoryStream()
        src.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
        Dim image As BitmapImage = New BitmapImage()
        image.BeginInit()
        ms.Seek(0, SeekOrigin.Begin)
        image.StreamSource = ms
        image.EndInit()
        IMGcontainer.Source = image
        Return image
    End Function
 

Обратите внимание, что в моем случае возврат не требуется, потому что я не мог понять, как обновить свойство при преобразовании, чтобы элемент управления изображением заметил. Вместо этого я просто устанавливаю свойство container Source .

Это довольно банально, но работает.

Вот полный класс APNGBox:

 Imports System
Imports System.Collections.Generic
Imports System.Drawing
Imports System.Windows.Forms
Imports APNGLib
'addition made by dumi
Imports System.IO
Imports System.Windows.Media.Imaging
Imports System.ComponentModel
'---------------------------------------------------------
Public Class APNGBox
    Inherits PictureBox
    'addition made by dumi
    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler _
        Implements INotifyPropertyChanged.PropertyChanged

    Public Sub NotifyPropertyChanged(ByVal info As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub
    '---------------------------------------------------------
    Public Property CurrentFrameNumber As Integer
    Public Property Images As IList(Of Bitmap)
    Private APNGFile As APNG
    'addition made by dumi
    Private IMGcontainer As System.Windows.Controls.Image
    '---------------------------------------------------------
    Private timer As Timer
    Private playthroughs As UInteger
    Private _ImageBitmap As BitmapImage

    'addition made by dumi
    Public Property ImageBitmap As BitmapImage
        Get
            Return _ImageBitmap
        End Get
        Set
            _ImageBitmap = Value
            NotifyPropertyChanged(NameOf(ImageBitmap))
        End Set
    End Property
    '---------------------------------------------------------

    Public Sub New(ByVal png As APNG, Container As System.Windows.Controls.Image)
        APNGFile = png
        'addition made by dumi
        IMGcontainer = Container
        '---------------------------------------------------------
        CurrentFrameNumber = 0
        Images = New List(Of Bitmap)()
        InitImages()
        'addition made by dumi
        ImageBitmap = Convert(Images(0))
        '---------------------------------------------------------
        Image = Images(0)
        Size = Image.Size
        playthroughs = 0

        If APNGFile.IsAnimated Then
            timer = New Timer()
            timer.Interval = APNGFile.GetFrame(0).Milliseconds
            AddHandler timer.Tick, New EventHandler(AddressOf timer_Tick)
        End If
    End Sub

    'addition made by dumi
    Public Function Convert(ByVal src As Bitmap) As BitmapImage
        Dim ms As MemoryStream = New MemoryStream()
        src.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
        Dim image As BitmapImage = New BitmapImage()
        image.BeginInit()
        ms.Seek(0, SeekOrigin.Begin)
        image.StreamSource = ms
        image.EndInit()
        IMGcontainer.Source = image
        Return image
    End Function
    '---------------------------------------------------------
    Private Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        If APNGFile.MaxPlays = 0 OrElse playthroughs < APNGFile.MaxPlays Then
            NextImage()
            Dim f As Frame = APNGFile.GetFrame(CurrentFrameNumber)
            timer.Interval = f.Milliseconds
        End If
    End Sub

    Private Sub InitImages()
        If APNGFile.IsAnimated Then
            Dim current As Bitmap = New Bitmap(CInt(APNGFile.Width), CInt(APNGFile.Height))
            Dim previous As Bitmap = Nothing
            ImageRender.RenderNextFrame(current, Point.Empty, APNGFile.ToBitmap(0), Frame.BlendOperation.SOURCE)
            Images.Add(New Bitmap(current))

            For i As Integer = 1 To APNGFile.FrameCount - 1
                Dim oldFrame As APNGLib.Frame = APNGFile.GetFrame(i - 1)
                Dim prev As Bitmap = If(previous Is Nothing, Nothing, New Bitmap(previous))

                If oldFrame.DisposeOp <> APNGLib.Frame.DisposeOperation.PREVIOUS Then
                    previous = New Bitmap(current)
                End If

                ImageRender.DisposeBuffer(current, New Rectangle(CInt(oldFrame.XOffset), CInt(oldFrame.YOffset), CInt(oldFrame.Width), CInt(oldFrame.Height)), oldFrame.DisposeOp, prev)
                Dim currFrame As APNGLib.Frame = APNGFile.GetFrame(i)
                ImageRender.RenderNextFrame(current, New Point(CInt(currFrame.XOffset), CInt(currFrame.YOffset)), APNGFile.ToBitmap(i), currFrame.BlendOp)
                Images.Add(New Bitmap(current))
            Next
        Else
            Images.Add(APNGFile.ToBitmap())
        End If
    End Sub

    Public Sub NextImage()
        CurrentFrameNumber  = 1

        If CurrentFrameNumber >= APNGFile.FrameCount Then
            playthroughs  = 1
            CurrentFrameNumber = 0
        End If
        'addition made by dumi
        ImageBitmap = Convert(Images(CurrentFrameNumber))
        '---------------------------------------------------------
        Image = Images(CurrentFrameNumber)
    End Sub

    Public Sub ToImage(ByVal index As Integer)
        'addition made by dumi
        ImageBitmap = Convert(Images(index))
        '---------------------------------------------------------
        Image = Images(index)
        CurrentFrameNumber = index
    End Sub

    Public Sub Start()
        If timer IsNot Nothing Then
            timer.Start()
        End If
    End Sub

    Public Sub [Stop]()
        If timer IsNot Nothing Then
            timer.[Stop]()
        End If
    End Sub
End Class

 

Это изображение добавлено в исходный код github с помощью winforms:
Это изображение добавлено в исходный код github

И это мой результат в wpf: Это из моего приложения wpf