Librería de Snippets para VB.NET !! (Compartan aquí sus snippets)
Eleкtro:
Cómo iniciar el programa warp-cli.exe de la VPN de Cloudflare Warp pasándole un comando
Un simple método para ejecutar el programa warp-cli.exe de la VPN de Cloudflare Warp pasándole un comando (ej. "connect", "disconnect", etc):
Código
''' <summary>
''' Sends a custom command to the Cloudflare Warp CLI executable (<c>warp-cli.exe</c>)
''' and captures both standard output and error output.
''' </summary>
'''
''' <param name="command">
''' The command-line argument to be passed to warp-cli executable.
''' For example: <c>connect</c>, <c>disconnect</c>, <c>status</c>, etc.
''' </param>
'''
''' <param name="refOutput">
''' Returns the standard output returned by the warp-cli process.
''' </param>
'''
''' <param name="refErrorOutput">
''' Returns the standard error output returned by the warp-cli process.
''' </param>
'''
''' <param name="warpCliFilePath">
''' Optional path to the warp-cli executable. If <c>Nothing</c> is specified, the method defaults to:
''' <c>%ProgramFiles%\Cloudflare\Cloudflare Warp\warp-cli.exe</c>.
''' </param>
'''
''' <returns>
''' The exit code returned by the warp-cli process. A value of 0 typically indicates success.
''' </returns>
'''
''' <exception cref="System.IO.FileNotFoundException">
''' Thrown if the specified or default warp-cli executable file is not found on the system.
''' </exception>
'''
''' <exception cref="System.TimeoutException">
''' Thrown if the warp-cli process takes longer than 60 seconds to complete.
''' </exception>
'''
''' <exception cref="System.Exception">
''' Thrown if any other unexpected error occurs while attempting to execute the warp-cli process.
''' The original exception is wrapped as the inner exception.
''' </exception>
<DebuggerStepThrough>
Public Shared Function CloudflareWarpCliSendCommand(command As String,
ByRef refOutput As String,
ByRef refErrorOutput As String,
Optional warpCliFilePath As String = Nothing) As Integer
' Prevents concurrent execution of the method from multiple threads within the same process.
' This static lock object ensures that only one thread can execute the critical section at a time,
' avoiding race conditions or conflicts when invoking the Warp CLI.
Static WarpCliLock As New Object()
Static spaceChar As Char = " "c
SyncLock WarpCliLock
If String.IsNullOrEmpty(warpCliFilePath) Then
warpCliFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"Cloudflare\Cloudflare Warp\warp-cli.exe")
End If
Try
If Not System.IO.File.Exists(warpCliFilePath) Then
Throw New System.IO.FileNotFoundException("The Warp CLI executable was not found.", warpCliFilePath)
End If
Using pr As New Process()
pr.StartInfo.FileName = warpCliFilePath
pr.StartInfo.Arguments = command
pr.StartInfo.UseShellExecute = False
pr.StartInfo.CreateNoWindow = True
pr.StartInfo.RedirectStandardOutput = True
pr.StartInfo.RedirectStandardError = True
pr.Start()
If Not pr.WaitForExit(60000) Then ' Waits a maximum of 60 seconds
pr.Kill()
Throw New TimeoutException("warp-cli process has timed out.")
End If
refOutput = pr.StandardOutput.ReadToEnd().Trim(Environment.NewLine.ToCharArray().Concat({spaceChar}).ToArray())
refErrorOutput = pr.StandardError.ReadToEnd().Trim(Environment.NewLine.ToCharArray().Concat({spaceChar}).ToArray())
Return pr.ExitCode
End Using
Catch ex As Exception
Throw New Exception($"Failed to execute warp-cli process. See inner exception for details.", ex)
End Try
End SyncLock
End Function
Casos de uso reales: para conectar a la red de Cloudflare WARP en cualquier proyecto donde hagamos solicitudes http, por ejemplo en un web-crawler, a sitios web con riesgo de que puedan acabar bloqueando nuestra IP.
Tres métodos de extensión para dibujar texto sobre una imagen, o dibujar encima otra imagen (con capacidad opcional de usar transparencia) o un valor numérico, con una escala proporcional a la imagen y en una posición alineada a cualquiera de las esquinas o zonas centrales de la imagen (centro absoluto, parte superior central o parte inferior central) de la imagen.
Demostración de resultado de la extensión que dibuja un valor numérico (de forma alineada a la esquina inferior derecha de la imagen):
Código
''' <summary>
''' Draws an overlay image onto the specified <see cref="Image"/> at a given position and scale factor.
''' </summary>
'''
''' <param name="refImg">
''' The source <see cref="Image"/> to modify. The overlay image will be drawn directly on this image.
''' </param>
'''
''' <param name="overlayImg">
''' The overlay image to draw on the source <paramref name="refImg"/>.
''' </param>
'''
''' <param name="scale">
''' The relative image scale factor to determine overlay image size. Lower values increase the size of the overlay image.
''' </param>
'''
''' <param name="position">
''' The position/alignment where the overlay image should be drawn (e.g., bottom-right).
''' </param>
'''
''' <param name="margin">
''' The margin (in pixels) from the edge of the image to position the overlay image.
''' <para></para>
''' This value has different meaning depending on <paramref name="position"/> parameter:
''' <para></para>
''' <list type="bullet">
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopLeft"/>, <see cref="ContentAlignment.TopRight"/>,
''' <para></para>
''' <see cref="ContentAlignment.BottomLeft"/> and <see cref="ContentAlignment.BottomRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the diagonal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleLeft"/> and <see cref="ContentAlignment.MiddleRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the horizontal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopCenter"/> and <see cref="ContentAlignment.BottomCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the vertical offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> is ignored.</description>
''' </item>
''' </list>
''' </param>
'''
''' <param name="transparentColor">
''' Optional. A <see cref="Color"/> to use as transparency to draw the overlay image.
''' </param>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Sub DrawImageScaled(ByRef refImg As Image, overlayImg As Image,
scale As Single, position As ContentAlignment, margin As Single,
Optional transparentColor As Color? = Nothing)
If refImg Is Nothing Then
Throw New ArgumentNullException(NameOf(refImg))
End If
If overlayImg Is Nothing Then
Throw New ArgumentNullException(NameOf(overlayImg))
End If
If margin < 0 Then
Throw New ArgumentOutOfRangeException(NameOf(margin), margin, "Margin must be greater than or equal to 0.")
End If
If scale < 1 Then
Throw New ArgumentOutOfRangeException(NameOf(scale), scale, "Font scale must be greater than or equal to 1.")
End If
Using g As Graphics = Graphics.FromImage(refImg)
g.SmoothingMode = SmoothingMode.AntiAlias
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.PixelOffsetMode = PixelOffsetMode.HighQuality
g.CompositingQuality = CompositingQuality.HighQuality
Dim targetSize As Single = Math.Max(refImg.Width, refImg.Height) / scale
Dim aspectRatio As Single = CSng(overlayImg.Width / overlayImg.Height)
Dim drawWidth As Single
Dim drawHeight As Single
If overlayImg.Width >= overlayImg.Height Then
drawWidth = targetSize
drawHeight = targetSize / aspectRatio
Else
drawHeight = targetSize
drawWidth = targetSize * aspectRatio
End If
Dim posX As Single = 0
Dim posY As Single = 0
Select Case position
Case ContentAlignment.TopLeft
posX = margin
posY = margin
Case ContentAlignment.TopCenter
posX = (refImg.Width - drawWidth) / 2
posY = margin
Case ContentAlignment.TopRight
posX = refImg.Width - drawWidth - margin
posY = margin
Case ContentAlignment.MiddleLeft
posX = margin
posY = (refImg.Height - drawHeight) / 2
Case ContentAlignment.MiddleCenter
posX = (refImg.Width - drawWidth) / 2
posY = (refImg.Height - drawHeight) / 2
Case ContentAlignment.MiddleRight
posX = refImg.Width - drawWidth - margin
posY = (refImg.Height - drawHeight) / 2
Case ContentAlignment.BottomLeft
posX = margin
posY = refImg.Height - drawHeight - margin
Case ContentAlignment.BottomCenter
posX = (refImg.Width - drawWidth) / 2
posY = refImg.Height - drawHeight - margin
Case ContentAlignment.BottomRight
posX = refImg.Width - drawWidth - margin
posY = refImg.Height - drawHeight - margin
Case Else
Throw New InvalidEnumArgumentException(NameOf(position), position, GetType(ContentAlignment))
End Select
If transparentColor.HasValue Then
Using attr As New Imaging.ImageAttributes()
attr.SetColorKey(transparentColor.Value, transparentColor.Value)
Dim destRect As New Rectangle(CInt(posX), CInt(posY), CInt(drawWidth), CInt(drawHeight))
g.DrawImage(overlayImg, destRect, 0, 0, overlayImg.Width, overlayImg.Height, GraphicsUnit.Pixel, attr)
End Using
Else
g.DrawImage(overlayImg, posX, posY, drawWidth, drawHeight)
End If
End Using
End Sub
''' <summary>
''' Draws text onto the specified <see cref="Image"/> at a given position and scale factor.
''' </summary>
'''
''' <param name="refImg">
''' The <see cref="Image"/> to modify. The text will be drawn directly on this image.
''' </param>
'''
''' <param name="text">
''' The text to draw on the image.
''' </param>
'''
''' <param name="scale">
''' The relative image scale factor to determine font size. Lower values increase the size of the text.
''' <para></para>
''' Suggested value is from 10 to 20.
''' </param>
'''
''' <param name="position">
''' The position/alignment where the text should be drawn (e.g., bottom-right).
''' </param>
'''
''' <param name="margin">
''' The margin (in pixels) from the edge of the image to position the text.
''' <para></para>
''' This value has different meaning depending on <paramref name="position"/> parameter:
''' <para></para>
''' <list type="bullet">
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopLeft"/>, <see cref="ContentAlignment.TopRight"/>,
''' <para></para>
''' <see cref="ContentAlignment.BottomLeft"/> and <see cref="ContentAlignment.BottomRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the diagonal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleLeft"/> and <see cref="ContentAlignment.MiddleRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the horizontal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopCenter"/> and <see cref="ContentAlignment.BottomCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the vertical offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> is ignored.</description>
''' </item>
''' </list>
''' </param>
'''
''' <param name="font">
''' Optional. A custom <see cref="Font"/> to use. If not provided, a bold <c>Arial</c> font is used.
''' <para></para>
''' Note: Custom font size (<see cref="System.Drawing.Font.Size"/>) is ignored. It is determined by <paramref name="scale"/> parameter.
''' </param>
'''
''' <param name="textColor">
''' Optional. The color of the text.
''' <para></para>
''' Default value is <see cref="Color.White"/>.
''' </param>
'''
''' <param name="outlineColor">
''' Optional. The color of the text outline.
''' <para></para>
''' Default value is <see cref="Color.Black"/>.
''' </param>
'''
''' <param name="outlineThickness">
''' Optional. The thickness of the outline, in pixels.
''' <para></para>
''' Default value is 2 pixels.
''' </param>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Sub DrawTextScaled(ByRef refImg As Image, text As String, scale As Single,
position As ContentAlignment, margin As Single,
Optional font As Font = Nothing,
Optional textColor As Color = Nothing,
Optional outlineColor As Color = Nothing,
Optional outlineThickness As Short = 2)
If margin < 0 Then
Throw New ArgumentOutOfRangeException(NameOf(margin), margin, "Margin must be greater than or equal to 0.")
End If
If scale < 1 Then
Throw New ArgumentOutOfRangeException(NameOf(scale), scale, "Font scale must be greater than or equal to 1.")
End If
If textColor = Nothing Then
textColor = Color.White
End If
If outlineColor = Nothing Then
outlineColor = Color.Black
End If
Using g As Graphics = Graphics.FromImage(refImg)
g.SmoothingMode = SmoothingMode.AntiAlias
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.PixelOffsetMode = PixelOffsetMode.HighQuality
g.CompositingQuality = CompositingQuality.HighQuality
Dim rawFontSize As Single = Math.Max(refImg.Width, refImg.Height) / scale
Dim maxAllowedFontSize As Single = Math.Min(refImg.Width, refImg.Height)
Dim fontSize As Single = Math.Min(rawFontSize, maxAllowedFontSize)
Using textFont As Font =
If(font IsNot Nothing, New Font(font.FontFamily, fontSize, font.Style, GraphicsUnit.Pixel, font.GdiCharSet, font.GdiVerticalFont),
New Font("Arial", fontSize, FontStyle.Bold, GraphicsUnit.Pixel))
Dim textSize As SizeF = g.MeasureString(text, textFont)
Dim posX As Single = 0
Dim posY As Single = 0
Select Case position
Case ContentAlignment.TopLeft
posX = margin
posY = margin
Case ContentAlignment.TopCenter
posX = (refImg.Width - textSize.Width) / 2
posY = margin
Case ContentAlignment.TopRight
posX = refImg.Width - textSize.Width - margin
posY = margin
Case ContentAlignment.MiddleLeft
posX = margin
posY = (refImg.Height - textSize.Height) / 2
Case ContentAlignment.MiddleCenter
posX = (refImg.Width - textSize.Width) / 2
posY = (refImg.Height - textSize.Height) / 2
Case ContentAlignment.MiddleRight
posX = refImg.Width - textSize.Width - margin
posY = (refImg.Height - textSize.Height) / 2
Case ContentAlignment.BottomLeft
posX = margin
posY = refImg.Height - textSize.Height - margin
Case ContentAlignment.BottomCenter
posX = (refImg.Width - textSize.Width) / 2
posY = refImg.Height - textSize.Height - margin
Case ContentAlignment.BottomRight
posX = refImg.Width - textSize.Width - margin
posY = refImg.Height - textSize.Height - margin
Case Else
Throw New InvalidEnumArgumentException(NameOf(position), position, GetType(ContentAlignment))
End Select
Using outlineBrush As New SolidBrush(outlineColor)
For dx As Short = -outlineThickness To outlineThickness
For dy As Short = -outlineThickness To outlineThickness
If dx <> 0 OrElse dy <> 0 Then
g.DrawString(text, textFont, outlineBrush, posX + dx, posY + dy)
End If
Next dy
Next dx
End Using
Using textBrush As New SolidBrush(textColor)
g.DrawString(text, textFont, textBrush, posX, posY)
End Using
End Using ' font
End Using ' g
End Sub
''' <summary>
''' Draws a number onto the specified <see cref="Image"/> at a given position and scale factor.
''' </summary>
'''
''' <param name="refImg">
''' The <see cref="Image"/> to modify. The number will be drawn directly on this image.
''' </param>
'''
''' <param name="number">
''' The number to draw on the image.
''' </param>
'''
''' <param name="scale">
''' The relative image scale factor to determine font size. Lower values increase the size of the text.
''' <para></para>
''' Suggested value is from 10 to 20.
''' </param>
'''
''' <param name="position">
''' The position/alignment where the number should be drawn (e.g., bottom-right).
''' </param>
'''
''' <param name="margin">
''' The margin (in pixels) from the edge of the image to position the text.
''' <para></para>
''' This value has different meaning depending on <paramref name="position"/> parameter:
''' <para></para>
''' <list type="bullet">
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopLeft"/>, <see cref="ContentAlignment.TopRight"/>,
''' <para></para>
''' <see cref="ContentAlignment.BottomLeft"/> and <see cref="ContentAlignment.BottomRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the diagonal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleLeft"/> and <see cref="ContentAlignment.MiddleRight"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the horizontal offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.TopCenter"/> and <see cref="ContentAlignment.BottomCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> specifies the vertical offset.</description>
''' </item>
''' <item>
''' <term>
''' <see cref="ContentAlignment.MiddleCenter"/>
''' </term>
''' <description><para></para><paramref name="margin"/> is ignored.</description>
''' </item>
''' </list>
''' </param>
'''
''' <param name="font">
''' Optional. A custom <see cref="Font"/> to use. If not provided, a bold <c>Arial</c> font is used.
''' <para></para>
''' Note: Custom font size (<see cref="System.Drawing.Font.Size"/>) is ignored. It is determined by <paramref name="scale"/> parameter.
''' </param>
'''
''' <param name="textColor">
''' Optional. The color of the text.
''' <para></para>
''' Default value is <see cref="Color.White"/>.
''' </param>
'''
''' <param name="outlineColor">
''' Optional. The color of the text outline.
''' <para></para>
''' Default value is <see cref="Color.Black"/>.
''' </param>
'''
''' <param name="outlineThickness">
''' Optional. The thickness of the outline, in pixels.
''' <para></para>
''' Default value is 2 pixels.
''' </param>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Sub DrawNumberScaled(ByRef refImg As Image, number As Integer, scale As Single,
position As ContentAlignment, margin As Single,
Optional font As Font = Nothing,
Optional textColor As Color = Nothing,
Optional outlineColor As Color = Nothing,
Optional outlineThickness As Short = 2)
DrawTextScaled(refImg, CStr(number), scale, position, margin, font, textColor, outlineColor, outlineThickness)
End Sub
Eleкtro:
Cuatro métodos de extensión para el tipo DateTime con los que obtener una representación de fecha o fecha y hora realmente amistosa.
Ejemplos:
Fecha en inglés: 11 May, 2025
Fecha en español: 11 de mayo de 2025
Fecha en alemán: 11. Mai 2025
Fecha y hora en inglés: 11 May, 2025 at 23:59:59
Fecha y hora en español: 11 de mayo de 2025 a las 23:59:59
No soy experto en la representación por escrito de fechas en otros idiomas así que solo intenté perfeccionar estos tres. La representación en alemán estaría bien según me he informado, ya que se supone que se añade un punto de esa forma. En definitiva, creo que para ir tirando está bien así.
Código
''' <summary>
''' Converts a <see cref="Date"/> object to a long friendly date string based on the current culture.
''' <para></para>
''' For example:
''' <list type="bullet">
''' <item><description>English<para></para>11 May, 2025</description></item>
''' <item><description>Spanish<para></para>11 de mayo de 2025</description></item>
''' <item><description>German<para></para>11. Mai 2025</description></item>
''' </list>
''' </summary>
'''
''' <param name="[date]">
''' The <see cref="Date"/> object to be formatted.
''' </param>
'''
''' <returns>
''' A string representing the formatted date, based on the current culture.
''' </returns>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function ToLongFriendlyDateString([date] As Date) As String
Return DateExtensions.ToLongFriendlyDateString([date], CultureInfo.CurrentCulture)
End Function
''' <summary>
''' Converts a <see cref="Date"/> object to a long friendly date string based on the specified culture.
''' <para></para>
''' For example:
''' <list type="bullet">
''' <item><description>English<para></para>11 May, 2025</description></item>
''' <item><description>Spanish<para></para>11 de mayo de 2025</description></item>
''' <item><description>German<para></para>11. Mai 2025</description></item>
''' </list>
''' </summary>
'''
''' <param name="[date]">
''' The <see cref="Date"/> object to be formatted.
''' </param>
'''
''' <param name="provider">
''' The culture information used to format the date.
''' </param>
'''
''' <returns>
''' A string representing the formatted date, based on the specified culture.
''' </returns>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function ToLongFriendlyDateString([date] As Date, provider As IFormatProvider) As String
Dim culture As CultureInfo = TryCast(provider, CultureInfo)
If culture IsNot Nothing Then
Select Case culture.TwoLetterISOLanguageName.ToLower()
Case "es", "ca", "gl", "pt" ' Spanish, Catalonian, Galego, Portuguese
Return [date].ToString("dd 'de' MMMM 'de' yyyy", provider)
Case "de" ' Deutsch
Return [date].ToString("dd'.' MMMM yyyy", provider)
Case Else ' Do nothing.
Exit Select
End Select
End If
Return [date].ToString("dd MMMM, yyyy", provider)
End Function
''' <summary>
''' Converts a <see cref="Date"/> object to a long friendly date string based on the current culture.
''' <para></para>
''' For example:
''' <list type="bullet">
''' <item><description>English<para></para>11 May, 2025 at 23:59:59</description></item>
''' <item><description>Spanish<para></para>11 de mayo de 2025 a las 23:59:59</description></item>
''' </list>
''' </summary>
'''
''' <param name="[date]">
''' The <see cref="Date"/> object to be formatted.
''' </param>
'''
''' <returns>
''' A string representing the formatted date, based on the current culture.
''' </returns>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function ToLongFriendlyDateAndTimeString([date] As Date) As String
Return DateExtensions.ToLongFriendlyDateAndTimeString([date], CultureInfo.CurrentCulture)
End Function
''' <summary>
''' Converts a <see cref="Date"/> object to a long friendly date string based on the specifies culture.
''' <para></para>
''' For example:
''' <list type="bullet">
''' <item><description>English<para></para>11 May, 2025 at 23:59:59</description></item>
''' <item><description>Spanish<para></para>11 de mayo de 2025 a las 23:59:59</description></item>
''' </list>
''' </summary>
'''
''' <param name="[date]">
''' The <see cref="Date"/> object to be formatted.
''' </param>
'''
''' <param name="provider">
''' The culture information used to format the date.
''' </param>
'''
''' <returns>
''' A string representing the formatted date, based on the specified culture.
''' </returns>
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function ToLongFriendlyDateAndTimeString([date] As Date, provider As IFormatProvider) As String
Dim culture As CultureInfo = TryCast(provider, CultureInfo)
If culture IsNot Nothing Then
Select Case culture.TwoLetterISOLanguageName.ToLower()
Case "en" ' English
Return [date].ToString($"'{ToLongFriendlyDateString([date], provider)}' 'at' HH:mm:ss", provider)
Case "es" ' Spanish
Return [date].ToString($"'{ToLongFriendlyDateString([date], provider)}' 'a las' HH:mm:ss", provider)
Case Else ' Do nothing.
Exit Select
End Select
End If
Return [date].ToString($"'{ToLongFriendlyDateString([date], provider)}' '—' HH:mm:ss", provider)
End Function
Eleкtro:
Librería .NET para automatizar el uso de rar.exe de RARLab (WinRAR)
Esto es un wrapper .NET completo para la herramienta por línea de comandos rar.exe oficial de RARLab. Esta librería permite a los desarrolladores de .NET acceder y controlar fácilmente casi todas las funciones de rar.exe, como comprimir, extraer, listar, testar, crear volúmenes de recuperación y administrar archivos RAR, desde sus aplicaciones.
Llevaba mucho tiempo queriendo hacer esto, bastantes años hace que se me ocurrió la idea por que hay infinidad de librerías disponibles en la mayoría de lenguajes de programación para manejar formatos ZIP y 7Zip entre otros muchos, pero para el formato RAR, en especial el formato RARv5 son muy escasas... probablemente por desinterés y/o por ser un formato privativo. Lo cierto es que no conozco ningún otro wrapper del executable rar.exe, ni tampoco un wrapper que en lugar de depender de rar.exe haga llamadas nativas a una librería oficial de RARLab.
El caso es que nunca empecé este proyecto por simple pereza. Me parecía muy interesante pero al mismo tiempo no me resultaba necesario en realidad desarrollar una infraestructura completa para configurar el lanzamiento del proceso de rar.exe pasándole un comando cualquiera, cosa que podía escribir en una sola línea como esta: Process.Start(".\rar.exe", "argumentos") — pero claro, esto es algo muy codificado en el código por así decirlo, no es tan bonito o elegante o profesional como configurar una sofisticada clase para construir los argumentos y controlar el lanzamiento del proceso con sus códigos de salida y demás.
Así que siempre lo estuve aplazando. Y cuando finalmente decidí empezar, hace cosa de unas semanas, esperaba poder compartirlo con ustedes en formato de "snippet" en este hilo, es decir algo de un tamaño reducido, pero fui demasiado ingenuo ya que al final el trabajo ha alcanzado la cantidad de 9 clases para representar diversos comandos, 17 enumeraciones y otras tantas clases para otros elementos integrados, haciendo un total de 37 archivos separados de código fuente.
Así que no me ha quedado más remedio que compartirlo en GitHub, y aquí lo comparto con ustedes:
👉 📦 RARLab's rar.exe .NET Wrapper Library
Como he dicho, esto es una librería, un archivo dll para administrar el uso del archivo rar.exe. Es totalmente "universal", se puede usar en proyectos de VB.NET o de C#, bajo .NET Framework o NET 5.0+ (el proyecto habría que migrarlo), no hay dependencias más allá del archivo 'rar.exe' de WinRAR y la licencia del producto, que deben ser administrados por el usuario.
El README.md del repositorio en GitHub incluye un ejemplo de uso para VB.NET y también para C#.
Además, en el código fuente de todas las nueve clases que representan los 'Comandos', incluyen un apartado, arriba del todo de la clase, con un ejemplo de uso para VB.NET, y también en la propia documentación XML de la clase.
De todas formas, aquí les dejo un ejemplo de uso completo para VB.NET
— Construir un Comando para la creación de archivos RAR utilizando la clase RarCreationCommand:
Código
Imports DevCase.RAR
Imports DevCase.RAR.Commands
Código
Dim archivePath As String = "C:\New Archive.rar"
Dim filesToAdd As String = "C:\Directory to add\"
Dim command As New RarCreationCommand(RarCreationMode.Add, archivePath, filesToAdd) With {
.RarExecPath = ".\rar.exe",
.RarLicenseData = "(Your license key)",
.RecurseSubdirectories = True,
.EncryptionProperties = Nothing,
.SolidCompression = False,
.CompressionMode = RarCompressionMode.Normal,
.DictionarySize = RarDictionarySize.Mb__128,
.OverwriteMode = RarOverwriteMode.Overwrite,
.FilePathMode = RarFilePathMode.ExcludeBaseDirFromFileNames,
.FileTimestamps = RarFileTimestamps.All,
.AddQuickOpenInformation = TriState.True,
.ProcessHardLinksAsLinks = True,
.ProcessSymbolicLinksAsLinks = TriState.True,
.DuplicateFileMode = RarDuplicateFileMode.Enabled,
.FileChecksumMode = RarFileChecksumMode.BLAKE2sp,
.ArchiveComment = New RarArchiveComment("Hello world!"),
.RecoveryRecordPercentage = 0,
.VolumeSplitOptions = Nothing,
.FileTypesToStore = Nothing
}
— Para obtener los argumentos completos de la línea de comandos de nuestro Comando:
Código
Console.WriteLine($"Command-line arguments: {command}")
Código
MessageBox.Show(command.ToString())
— Ejecutar nuestro Comando usando la clase RarCommandExecutor:
Código
Using rarExecutor As New RarCommandExecutor(command)
AddHandler rarExecutor.OutputDataReceived,
Sub(sender As Object, e As DataReceivedEventArgs)
Console.WriteLine($"[Output] {Date.Now:yyyy-MM-dd HH:mm:ss} - {e.Data}")
End Sub
AddHandler rarExecutor.ErrorDataReceived,
Sub(sender As Object, e As DataReceivedEventArgs)
If e.Data IsNot Nothing Then
Console.WriteLine($"[Error] {Date.Now:yyyy-MM-dd HH:mm:ss} - {e.Data}")
End If
End Sub
AddHandler rarExecutor.Exited,
Sub(sender As Object, e As EventArgs)
Dim pr As Process = DirectCast(sender, Process)
Dim rarExitCode As RarExitCode = DirectCast(pr.ExitCode, RarExitCode)
Console.WriteLine($"[Exited] {Date.Now:yyyy-MM-dd HH:mm:ss} - rar.exe process has terminated with exit code {pr.ExitCode} ({rarExitCode})")
End Sub
Dim exitcode As RarExitCode = rarExecutor.ExecuteRarAsync().Result
End Using
**Aincrad**:
Genial snippets nuevos , gracias. ;-)
Eleкtro:
Cita de: **Aincrad** en 1 Junio 2025, 23:45 pm
Genial snippets nuevos , gracias. ;-)
Te lo agradezco!
Varios métodos para crear efectos de transición de imagen con la librería ImageMagick:
Magick.NET-Q8-AnyCPUMagick.NET-Q16-AnyCPU
El número de frames del efecto de transición y el tiempo de la secuencia de animación son configurables.
Estos efectos son ideales para generar presentaciones de imágenes en animaciones GIF...
Barrido direccional:
Código
''' <summary>
''' Generates a sequence of transition frames between two <see cref="MagickImage"/> instances,
''' progressively revealing the second image over the first one in a specified direction.
''' </summary>
'''
''' <param name="firstImage">
''' The starting image of the transition.
''' </param>
'''
''' <param name="secondImage">
''' The image to swipe in over <paramref name="firstImage"/>.
''' </param>
'''
''' <param name="direction">
''' The direction in which the swipe effect must occur.
''' </param>
'''
''' <param name="steps">
''' The number of intermediate frames to generate for the transition.
''' <para></para>
''' A higher value may result in a smoother, slower visual transition,
''' at the cost of increased processing time to generate the effect
''' and increased number of images / file size for the resulting animation.
''' <para></para>
''' Minimum value is 3. Default value is 5.
''' </param>
'''
''' <param name="animationDelay">
''' The time in 1/100ths of a second which must expire before splaying the next image in the transition sequence.
''' <para></para>
''' Default value is 1 (10 milliseconds).
''' </param>
'''
''' <param name="frameTransformation">
''' An <see cref="Action(Of MagickImage)"/> delegate that applies custom transformations to each frame (<see cref="MagickImage"/> object)
''' used to create the transition animation. This allows fine-tuning of image properties such as format,
''' color profile, quality and other supported properties and methods by <see cref="MagickImage"/> class.
''' <para></para>
''' Note: <paramref name="animationDelay"/> value cannot be overridden in <paramref name="frameTransformation"/> delegate.
''' <para></para>
''' Code Example in VB.NET:
''' <code>Dim transformation As Action(Of MagickImage) =
''' Sub(x As MagickImage)
''' x.AnimationDelay = 1 ' 10 milliseconds
''' x.Format = MagickFormat.Jpg
''' x.Quality = 90
''' End Sub
'''</code>
'''
''' Code Example in C#:
''' <code>Action<MagickImage> transformation = (MagickImage x) => {
''' x.AnimationDelay = 1; // 1 10 milliseconds
''' x.Format = MagickFormat.Jpg;
''' x.Quality = 90;
''' };</code>
''' </param>
'''
''' <returns>
''' An <see cref="IList"/> of <see cref="MagickImage"/> objects representing each frame of the transition animation.
''' <para></para>
''' All frames returned must be disposed of by the caller to free resources when no longer needed.
''' </returns>
<DebuggerStepThrough>
Public Shared Function GenerateSwipeTransition(firstImage As MagickImage, secondImage As MagickImage,
direction As System.Windows.Forms.FlowDirection,
steps As Integer, animationDelay As Integer,
Optional frameTransformation As Action(Of MagickImage) = Nothing) As IList(Of MagickImage)
If firstImage Is Nothing Then
Throw New ArgumentNullException(NameOf(firstImage))
End If
If secondImage Is Nothing Then
Throw New ArgumentNullException(NameOf(secondImage))
End If
If steps < 3 Then
Throw New ArgumentOutOfRangeException(NameOf(steps), steps,
"The steps value must be equal to or greater than three.")
End If
If animationDelay <= 0 Then
Throw New ArgumentOutOfRangeException(NameOf(animationDelay), animationDelay,
"The animation delay value must be greater than zero.")
End If
Dim frames As New List(Of MagickImage)
For i As Integer = 1 To steps
Dim ratio As Double = i / steps
Using secondCropped As New MagickImage(secondImage)
Dim cropWidth As UInteger = secondImage.Width
Dim cropHeight As UInteger = secondImage.Height
Dim offsetX As Integer = 0
Dim offsetY As Integer = 0
Dim drawX As Integer = 0
Dim drawY As Integer = 0
Select Case direction
Case System.Windows.Forms.FlowDirection.LeftToRight
cropWidth = CUInt(secondImage.Width * ratio)
offsetX = 0
drawX = 0
Case System.Windows.Forms.FlowDirection.RightToLeft
cropWidth = CUInt(secondImage.Width * ratio)
offsetX = CInt(secondImage.Width - cropWidth)
drawX = offsetX
Case System.Windows.Forms.FlowDirection.TopDown
cropHeight = CUInt(secondImage.Height * ratio)
offsetY = 0
drawY = 0
Case System.Windows.Forms.FlowDirection.BottomUp
cropHeight = CUInt(secondImage.Height * ratio)
offsetY = CInt(secondImage.Height - cropHeight)
drawY = offsetY
End Select
Dim geometry As New MagickGeometry(offsetX, offsetY, cropWidth, cropHeight)
secondCropped.Crop(geometry)
secondCropped.ResetPage()
Dim frame As New MagickImage(firstImage)
frame.Composite(secondCropped, drawX, drawY, CompositeOperator.Over)
frameTransformation?.Invoke(frame)
frame.AnimationDelay = CUInt(animationDelay)
frames.Add(frame)
End Using
Next
Return frames
End Function
Fundido de entrada de imagen B sobre imagen A:
Código
''' <summary>
''' Generates a sequence of transition frames between two <see cref="MagickImage"/> instances,
''' gradually fading in the second image over the first one.
''' </summary>
'''
''' <param name="firstImage">
''' The starting image of the transition.
''' </param>
'''
''' <param name="secondImage">
''' The image to fade in over <paramref name="firstImage"/>.
''' </param>
'''
''' <param name="steps">
''' The number of intermediate frames to generate for the transition.
''' <para></para>
''' A higher value may result in a smoother, slower visual transition,
''' at the cost of increased processing time to generate the effect
''' and increased number of images / file size for the resulting animation.
''' <para></para>
''' Minimum value is 3. Default value is 5.
''' </param>
'''
''' <param name="animationDelay">
''' The time in 1/100ths of a second which must expire before splaying the next image in the transition sequence.
''' <para></para>
''' Default value is 1 (10 milliseconds).
''' </param>
'''
''' <param name="frameTransformation">
''' An <see cref="Action(Of MagickImage)"/> delegate that applies custom transformations to each frame (<see cref="MagickImage"/> object)
''' used to create the transition animation. This allows fine-tuning of image properties such as format,
''' color profile, quality and other supported properties and methods by <see cref="MagickImage"/> class.
''' <para></para>
''' Note: <paramref name="animationDelay"/> value cannot be overridden in <paramref name="frameTransformation"/> delegate.
''' <para></para>
''' Code Example in VB.NET:
''' <code>Dim transformation As Action(Of MagickImage) =
''' Sub(x As MagickImage)
''' x.AnimationDelay = 1 ' 10 milliseconds
''' x.Format = MagickFormat.Jpg
''' x.Quality = 90
''' End Sub
'''</code>
'''
''' Code Example in C#:
''' <code>Action<MagickImage> transformation = (MagickImage x) => {
''' x.AnimationDelay = 1; // 1 10 milliseconds
''' x.Format = MagickFormat.Jpg;
''' x.Quality = 90;
''' };</code>
''' </param>
'''
''' <returns>
''' An <see cref="IList"/> of <see cref="MagickImage"/> objects representing each frame of the transition animation.
''' <para></para>
''' All frames returned must be disposed of by the caller to free resources when no longer needed.
''' </returns>
<DebuggerStepThrough>
Public Shared Function GenerateFadeInOverTransition(firstImage As MagickImage, secondImage As MagickImage,
steps As Integer, animationDelay As Integer,
Optional frameTransformation As Action(Of MagickImage) = Nothing) As IList(Of MagickImage)
If firstImage Is Nothing Then
Throw New ArgumentNullException(NameOf(firstImage))
End If
If secondImage Is Nothing Then
Throw New ArgumentNullException(NameOf(secondImage))
End If
If steps < 3 Then
Throw New ArgumentOutOfRangeException(NameOf(steps), steps,
"The steps value must be equal to or greater than three.")
End If
If animationDelay <= 0 Then
Throw New ArgumentOutOfRangeException(NameOf(animationDelay), animationDelay,
"The animation delay value must be greater than zero.")
End If
Dim frames As New List(Of MagickImage)
For i As Integer = 0 To steps
Dim alpha As Double = i / steps
Dim frame As New MagickImage(firstImage)
Using overlay As New MagickImage(secondImage)
overlay.Alpha(AlphaOption.On)
overlay.Evaluate(Channels.Alpha, EvaluateOperator.Multiply, alpha)
frame.Composite(overlay, CompositeOperator.Over)
frameTransformation?.Invoke(frame)
frame.AnimationDelay = CUInt(animationDelay)
frames.Add(frame)
End Using
Next
Return frames
End Function
Fundido de entrada negro:
Código
''' <summary>
''' Generates a sequence of transition frames, gradually fading in from black the specified <see cref="MagickImage"/> object.
''' </summary>
'''
''' <param name="image">
''' The <see cref="MagickImage"/> object to fade in from black.
''' </param>
'''
''' <param name="steps">
''' The number of intermediate frames to generate for the transition.
''' <para></para>
''' A higher value may result in a smoother, slower visual transition,
''' at the cost of increased processing time to generate the effect
''' and increased number of images / file size for the resulting animation.
''' <para></para>
''' Minimum value is 3. Default value is 5.
''' </param>
'''
''' <param name="animationDelay">
''' The time in 1/100ths of a second which must expire before splaying the next image in the transition sequence.
''' <para></para>
''' Default value is 1 (10 milliseconds).
''' </param>
'''
''' <param name="frameTransformation">
''' An <see cref="Action(Of MagickImage)"/> delegate that applies custom transformations to each frame (<see cref="MagickImage"/> object)
''' used to create the transition animation. This allows fine-tuning of image properties such as format,
''' color profile, quality and other supported properties and methods by <see cref="MagickImage"/> class.
''' <para></para>
''' Note: <paramref name="animationDelay"/> value cannot be overridden in <paramref name="frameTransformation"/> delegate.
''' <para></para>
''' Code Example in VB.NET:
''' <code>Dim transformation As Action(Of MagickImage) =
''' Sub(x As MagickImage)
''' x.AnimationDelay = 1 ' 10 milliseconds
''' x.Format = MagickFormat.Jpg
''' x.Quality = 90
''' End Sub
'''</code>
'''
''' Code Example in C#:
''' <code>Action<MagickImage> transformation = (MagickImage x) => {
''' x.AnimationDelay = 1; // 1 10 milliseconds
''' x.Format = MagickFormat.Jpg;
''' x.Quality = 90;
''' };</code>
''' </param>
'''
''' <returns>
''' An <see cref="IList"/> of <see cref="MagickImage"/> objects representing each frame of the transition animation.
''' <para></para>
''' All frames returned must be disposed of by the caller to free resources when no longer needed.
''' </returns>
<DebuggerStepThrough>
Public Shared Function GenerateFadeInFromBlackTransition(image As MagickImage,
steps As Integer, animationDelay As Integer,
Optional frameTransformation As Action(Of MagickImage) = Nothing) As IList(Of MagickImage)
If image Is Nothing Then
Throw New ArgumentNullException(NameOf(image))
End If
If steps < 3 Then
Throw New ArgumentOutOfRangeException(NameOf(steps), steps,
"The steps value must be equal to or greater than three.")
End If
If animationDelay <= 0 Then
Throw New ArgumentOutOfRangeException(NameOf(animationDelay), animationDelay,
"The animation delay value must be greater than zero.")
End If
Dim frames As New List(Of MagickImage)
Using black As New MagickImage(MagickColors.Black, image.Width, image.Height)
For i As Integer = 0 To steps
Dim alpha As Double = i / steps
Using fadeImg As New MagickImage(image)
fadeImg.Alpha(AlphaOption.On)
fadeImg.Evaluate(Channels.Alpha, EvaluateOperator.Multiply, alpha)
Dim background As New MagickImage(black)
background.Composite(fadeImg, CompositeOperator.Over)
frameTransformation?.Invoke(background)
background.AnimationDelay = CUInt(animationDelay)
frames.Add(background)
End Using
Next
End Using
Return frames
End Function
Fundido de salida a negro para la imagen A, y fundido de entrada desde negro para la imagen B:
Código
''' <summary>
''' Generates a sequence of transition frames between two <see cref="MagickImage"/> instances,
''' gradually fading out to black the first image, then fading in from black the second image.
''' </summary>
'''
''' <param name="firstImage">
''' The image to fade out to black.
''' </param>
'''
''' <param name="secondImage">
''' The image to fade in from black.
''' </param>
'''
''' <param name="steps">
''' The number of intermediate frames to generate for the transition.
''' <para></para>
''' A higher value may result in a smoother, slower visual transition,
''' at the cost of increased processing time to generate the effect
''' and increased number of images / file size for the resulting animation.
''' <para></para>
''' Minimum value is 3. Default value is 5.
''' </param>
'''
''' <param name="animationDelay">
''' The time in 1/100ths of a second which must expire before splaying the next image in the transition sequence.
''' <para></para>
''' Default value is 1 (10 milliseconds).
''' </param>
'''
''' <param name="frameTransformation">
''' An <see cref="Action(Of MagickImage)"/> delegate that applies custom transformations to each frame (<see cref="MagickImage"/> object)
''' used to create the transition animation. This allows fine-tuning of image properties such as format,
''' color profile, quality and other supported properties and methods by <see cref="MagickImage"/> class.
''' <para></para>
''' Note: <paramref name="animationDelay"/> value cannot be overridden in <paramref name="frameTransformation"/> delegate.
''' <para></para>
''' Code Example in VB.NET:
''' <code>Dim transformation As Action(Of MagickImage) =
''' Sub(x As MagickImage)
''' x.AnimationDelay = 1 ' 10 milliseconds
''' x.Format = MagickFormat.Jpg
''' x.Quality = 90
''' End Sub
'''</code>
'''
''' Code Example in C#:
''' <code>Action<MagickImage> transformation = (MagickImage x) => {
''' x.AnimationDelay = 1; // 1 10 milliseconds
''' x.Format = MagickFormat.Jpg;
''' x.Quality = 90;
''' };</code>
''' </param>
'''
''' <returns>
''' An <see cref="IList"/> of <see cref="MagickImage"/> objects representing each frame of the transition animation.
''' <para></para>
''' All frames returned must be disposed of by the caller to free resources when no longer needed.
''' </returns>
<DebuggerStepThrough>
Public Shared Function GenerateFadeOutAndFadeInToBlackTransition(firstImage As MagickImage, secondImage As MagickImage,
steps As Integer, animationDelay As Integer,
Optional frameTransformation As Action(Of MagickImage) = Nothing) As IList(Of MagickImage)
If firstImage Is Nothing Then
Throw New ArgumentNullException(NameOf(firstImage))
End If
If secondImage Is Nothing Then
Throw New ArgumentNullException(NameOf(secondImage))
End If
If steps < 3 Then
Throw New ArgumentOutOfRangeException(NameOf(steps), steps,
"The steps value must be equal to or greater than three.")
End If
If animationDelay <= 0 Then
Throw New ArgumentOutOfRangeException(NameOf(animationDelay), animationDelay,
"The animation delay value must be greater than zero.")
End If
Dim frames As New List(Of MagickImage)
Using blackImage As New MagickImage(MagickColors.Black, firstImage.Width, firstImage.Height)
' PHASE 1: Fade firstImage to black
For i As Integer = 0 To steps
Dim alpha As Double = 1.0 - (i / steps)
Dim background As New MagickImage(blackImage)
firstImage.Alpha(AlphaOption.On)
firstImage.Evaluate(Channels.Alpha, EvaluateOperator.Multiply, alpha)
background.Composite(firstImage, CompositeOperator.Over)
frameTransformation?.Invoke(background)
background.AnimationDelay = CUInt(animationDelay)
frames.Add(background)
Next
' PHASE 2: Fade in secondImage from black
For i As Integer = 1 To steps ' Empieza en 1 para no duplicar el frame negro
Dim alpha As Double = i / steps
Using baseImage As New MagickImage(secondImage)
Dim background As New MagickImage(blackImage)
baseImage.Alpha(AlphaOption.On)
baseImage.Evaluate(Channels.Alpha, EvaluateOperator.Multiply, alpha)
background.Composite(baseImage, CompositeOperator.Over)
frameTransformation?.Invoke(background)
background.AnimationDelay = CUInt(animationDelay)
frames.Add(background)
End Using
Next
Return frames
End Using
End Function
Fundido de salida a negro:
Código
''' <summary>
''' Generates a sequence of transition frames, gradually fading out to black the specified <see cref="MagickImage"/> object.
''' </summary>
'''
''' <param name="image">
''' The <see cref="MagickImage"/> object to fade out to black.
''' </param>
'''
''' <param name="steps">
''' The number of intermediate frames to generate for the transition.
''' <para></para>
''' A higher value may result in a smoother, slower visual transition,
''' at the cost of increased processing time to generate the effect
''' and increased number of images / file size for the resulting animation.
''' <para></para>
''' Minimum value is 3. Default value is 5.
''' </param>
'''
''' <param name="animationDelay">
''' The time in 1/100ths of a second which must expire before splaying the next image in the transition sequence.
''' <para></para>
''' Default value is 1 (10 milliseconds).
''' </param>
'''
''' <param name="frameTransformation">
''' An <see cref="Action(Of MagickImage)"/> delegate that applies custom transformations to each frame (<see cref="MagickImage"/> object)
''' used to create the transition animation. This allows fine-tuning of image properties such as format,
''' color profile, quality and other supported properties and methods by <see cref="MagickImage"/> class.
''' <para></para>
''' Note: <paramref name="animationDelay"/> value cannot be overridden in <paramref name="frameTransformation"/> delegate.
''' <para></para>
''' Code Example in VB.NET:
''' <code>Dim transformation As Action(Of MagickImage) =
''' Sub(x As MagickImage)
''' x.Format = MagickFormat.Jpg
''' x.Quality = 90
''' End Sub
'''</code>
'''
''' Code Example in C#:
''' <code>Action<MagickImage> transformation = (MagickImage x) => {
''' x.AnimationDelay = 1; // 1 10 milliseconds
''' x.Format = MagickFormat.Jpg;
''' x.Quality = 90;
''' };</code>
''' </param>
'''
''' <returns>
''' An <see cref="IList"/> of <see cref="MagickImage"/> objects representing each frame of the transition animation.
''' <para></para>
''' All frames returned must be disposed of by the caller to free resources when no longer needed.
''' </returns>
<DebuggerStepThrough>
Public Shared Function GenerateFadeOutToBlackTransition(image As MagickImage,
steps As Integer, animationDelay As Integer,
Optional frameTransformation As Action(Of MagickImage) = Nothing) As IList(Of MagickImage)
If image Is Nothing Then
Throw New ArgumentNullException(NameOf(image))
End If
If steps < 3 Then
Throw New ArgumentOutOfRangeException(NameOf(steps), steps,
"The steps value must be equal to or greater than three.")
End If
If animationDelay <= 0 Then
Throw New ArgumentOutOfRangeException(NameOf(animationDelay), animationDelay,
"The animation delay value must be greater than zero.")
End If
Dim frames As New List(Of MagickImage)
Using black As New MagickImage(MagickColors.Black, image.Width, image.Height)
For i As Integer = 0 To steps
Dim alpha As Double = 1.0 - (i / steps)
Using fadeImg As New MagickImage(image)
fadeImg.Alpha(AlphaOption.On)
fadeImg.Evaluate(Channels.Alpha, EvaluateOperator.Multiply, alpha)
Dim background As New MagickImage(black)
background.Composite(fadeImg, CompositeOperator.Over)
frameTransformation?.Invoke(background)
background.AnimationDelay = CUInt(animationDelay)
frames.Add(background)
End Using
Next
End Using
Return frames
End Function
Nota: además de esto escribí un método para generar un GIF animado a partir de un array de imágenes, pero no puedo compartirlo aquí ya que utiliza diversos elementos de mi librería comercial y es mucho lío extraer por separado cada código necesario para insertarlo y compartirlo aquí.
Navegación
[*] Página Anterior