Animar Gif como fondo de escritorio, va muy lento.

Iniciado por **Aincrad**, 18 Mayo 2021, 15:23 PM

0 Miembros y 1 Visitante están viendo este tema.

**Aincrad**

Hola, tengo una duda, haber si alguien podria ayudarme.

Estoy intentando poner un gif de fondo de pantalla , para eso... se me ocurre obtener cada frame del gif y cada frame , lo pongo de fondo de escritorio. pero el problema es que va lageado.

Esto es lo que estoy haciando :


Para manipular el Gif , uso la clase de elektro, yo hice la mia, pero consume mucha memoria. asi que F.

Clase : https://foro.elhacker.net/net/libreria_de_snippets_para_vbnet_compartan_aqui_sus_snippets-t378770.0.html;msg2116514#msg2116514


Y lo que estoy haciendo :

Código (vbnet) [Seleccionar]


'   StartEngine("C:\Users\S4Lsalsoft\Pictures\06bdf8ad69ff62062ae7dceb250d8866.gif")

    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function SystemParametersInfo(ByVal uAction As Integer, ByVal uParam As Integer, ByVal lpvParam As String, ByVal fuWinIni As Integer) As Integer
    End Function

    Const SPI_SETDESKWALLPAPER As Integer = 20
    Const SPIF_UPDATEINIFILE As Integer = &H1
    Const SPIF_SENDWININICHANGE As Integer = &H2



Public Sub StartEngine(ByVal GifPath As String)
         Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey("Control Panel\Desktop", True)
        key.SetValue("WallpaperStyle", 1.ToString())
        key.SetValue("TileWallpaper", 0.ToString())
        key.Dispose()

        Dim Asynctask As New Task(New Action(Sub()

                                                 Dim gif As New GIF(GifPath)

                                                 Do Until gif.EndOfFrames ' Iterate frames until the end of frame count.
                                                     Dim CurrentFrame As Image = gif.NextFrame()

                                                     CurrentFrame.Save("BackgroundFrames\displayImage" & gif.ActiveFrameIndex & ".bmp")
                                                     CurrentFrame.Dispose()

                                                     Dim tempPath As String = Path.Combine(Application.StartupPath, "BackgroundFrames\displayImage" & gif.ActiveFrameIndex & ".bmp")
                                                     SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, tempPath, SPIF_UPDATEINIFILE Or SPIF_SENDWININICHANGE)

                                                     '   Thread.Sleep(60) ' Simulate a FPS thingy.
                                                     Application.DoEvents()

                                                     If (gif.EndOfFrames) Then
                                                         ' Set active frame to 0 for infinite loop:
                                                         gif.ActiveFrameIndex = 0
                                                     End If

                                                 Loop

                                             End Sub), TaskCreationOptions.PreferFairness)
        Asynctask.Start()

    End Sub




Funciona pero va muy lento , alguna solucion? , gracias de antemano .






Serapis

El principal problema de la lentitud, recáe en que un gif, es una cantidad de frames comprimidos y con transparencia (habitualmente), luego meterlo en un bucle, exige cada vez tener que descomprimir cada frame y recalcular y luego además como has elegido el modo 'tile', lo que supone que cada frame se repetirá hasta completar el tamaño de la pantalla, con tantas filas y columnas como se precisen (o recortar la imagen si excediera el tamaño de la pantalla).

Un típico visualizador de gif, lo que hace es en primer lugar extraer cada frame, esto es descomprimirlo y calcular la transparencia respecto del previo, de modo que se obtienen los frames descomprimidos simplemente como un 'picture' (un bitmap), serán luego esos bitmaps, los que iteren en el bucle... pero solo se descomprimen del fichero una sola vez. Ahí radica la principal desventaja de tu código.


array de picture  bitmaps()
entero numFrames

numframes = funcion ExtraerFrames(gif gif)
    picture  frame, framefull
    dimensionar bitmaps(0 a gif.NumFrames)
 
    por cada frame en gif.Frames
        frameFull = ResizeFrame(desktop.width, desktop.Height, frame, tile)
        bitmaps(x)= frameFull
        x+=1
    siguiente

    devolver gif.NumFrames
fin funcion

Una vez tomados los frames, ya puedes en tu bucle rotar entre entre ellos pero ahora de un array de imágenes, que no necesitan ser descomprimidas cada vez (aunque ignoro si tu objeto gif, ya las tiene extraídas de una vez) y que ya cada uno tiene ahora el tamaño del escritorio (y no escalar con cada cambio de imagen).
Por supuesto ahora teniendo cada imagen el tamaño del escritorio, debería signarse 'centrado' no 'tile' (que se retiene en la imagen)...
Por último, deberías detectar si hay cambio de orientación o del tamaño del escritorio (el cambio de orientación es un cambio de tamaño, excepto cuando rota 180º), para readaptar (invocar de nuevo el código previo para reconstruir) los frames al nuevo tamaño del escritorio.

Pero insisto en que no es buena idea hacer que el escritorio cambie constantemente su fondo.
El escritorio es la ventana 0, todo el resto del IDE de windows cuelga de él, es la raíz.
Cualquier sobrecarga en el uso o refresco del escritorio, supone un lastre para el resto.
Piensa que otro agravio en la lentitud, es que el escritorio ha de recortar todos los elementos que contiene para pegar la imagen... Si al menos estuviera vacío... se evitaría el recorte, pero claro entonces no se distinguiría de un 'salvapantallas'...

Como mínimo en tu bucle o bien pones un intervalo alto entre cambio de imágenes... o que se detenga cuando descubra que otros procesos (que no son el tuyo), consumen/demandan recursos del procesador...

**Aincrad**

Cita de: Serapis en 18 Mayo 2021, 16:55 PM
El principal problema de la lentitud, recáe en que un gif, es una cantidad de frames comprimidos y con transparencia (habitualmente), luego meterlo en un bucle, exige cada vez tener que descomprimir cada frame y recalcular y luego además como has elegido el modo 'tile', lo que supone que cada frame se repetirá hasta completar el tamaño de la pantalla, con tantas filas y columnas como se precisen (o recortar la imagen si excediera el tamaño de la pantalla).

Un típico visualizador de gif, lo que hace es en primer lugar extraer cada frame, esto es descomprimirlo y calcular la transparencia respecto del previo, de modo que se obtienen los frames descomprimidos simplemente como un 'picture' (un bitmap), serán luego esos bitmaps, los que iteren en el bucle... pero solo se descomprimen del fichero una sola vez. Ahí radica la principal desventaja de tu código.


array de picture  bitmaps()
entero numFrames

numframes = funcion ExtraerFrames(gif gif)
    picture  frame, framefull
    dimensionar bitmaps(0 a gif.NumFrames)
 
    por cada frame en gif.Frames
        frameFull = ResizeFrame(desktop.width, desktop.Height, frame, tile)
        bitmaps(x)= frameFull
        x+=1
    siguiente

    devolver gif.NumFrames
fin funcion

Una vez tomados los frames, ya puedes en tu bucle rotar entre entre ellos pero ahora de un array de imágenes, que no necesitan ser descomprimidas cada vez (aunque ignoro si tu objeto gif, ya las tiene extraídas de una vez) y que ya cada uno tiene ahora el tamaño del escritorio (y no escalar con cada cambio de imagen).
Por supuesto ahora teniendo cada imagen el tamaño del escritorio, debería signarse 'centrado' no 'tile' (que se retiene en la imagen)...
Por último, deberías detectar si hay cambio de orientación o del tamaño del escritorio (el cambio de orientación es un cambio de tamaño, excepto cuando rota 180º), para readaptar (invocar de nuevo el código previo para reconstruir) los frames al nuevo tamaño del escritorio.

Pero insisto en que no es buena idea hacer que el escritorio cambie constantemente su fondo.
El escritorio es la ventana 0, todo el resto del IDE de windows cuelga de él, es la raíz.
Cualquier sobrecarga en el uso o refresco del escritorio, supone un lastre para el resto.
Piensa que otro agravio en la lentitud, es que el escritorio ha de recortar todos los elementos que contiene para pegar la imagen... Si al menos estuviera vacío... se evitaría el recorte, pero claro entonces no se distinguiría de un 'salvapantallas'...

Como mínimo en tu bucle o bien pones un intervalo alto entre cambio de imágenes... o que se detenga cuando descubra que otros procesos (que no son el tuyo), consumen/demandan recursos del procesador...

Gracias bro, voy a dejar la idea de cambiar constantemente el fondo de pantalla. e intentare dibujar directamente en el escritorio , debajo de los iconos. es muchísimo mas rapido, y no sobrecarga el escritorio.





**Aincrad**

#3
Solucionado!


Tuve que convertir mucho código de c++ y c# a vb , pero valio la pena :



Solo faltan algunos ajustes.