Extraer los frames de un gif animado en .NET
Introducción:
A estas alturas creo que no descubro nada si indico que para mostrar un gif animado en una aplicación Windows por ejemplo, basta con agregar el gif animado al control Image.
De esta manera, el gif animado se mostrará en toda su «expresión».
Ahora bien,… imaginemos que lo que queremos es extraer el contenido (los frames) de un gif animado.
¿Cómo lo haríamos?.
Eso es lo que vamos a ver en esta entrada, pero antes, un poco de chicha (si te aburro, puedes ir directamente al código 😀 ).
Conociendo un poco más un gif animado:
Un gif animado no es otra cosa que un repositorio compuesto por un conjunto de imágenes gif en orden secuencial.
El formato Gif tiene su origen en el año 1987 (ver referencias para concocer más acerca de Gif), y la bondad de los gifs animados es que gracias a ellos podíamos utilizar en Internet lo que se denominarían banners, término que aún hoy se usa. El formato gif animado sufrió diferentes modificaciones, de hecho se conocen dos formatos, 87A y 89A. El segundo acepta además transparencias.
Lo más interesante de un gif animado es que además de poder contener una secuencia de imágenes gif en un orden determinado, podíamos indicar una frecuencia, delay y otras propiedades propias para cada frame, de tal modo que si queríamos que un frame de la secuencia durara 2 segundos por ejemplo, lo podíamos realizar sin complicaciones.
No me quiero extender más sobre los gifs animados, para eso hay mucha información en Internet.
En referencias os indico un enlace con información adicional.
Posteriormente surgiría el formato png que tenía como objetivo cubrir dos aspectos inherentes a los gifs y que desquiciaban a los diseñadores y empresas.
Por un lado, utilizar un algoritmo de compresión sin pérdida aparente (el algoritmo LZW de gif sí tenía este problema de pérdida de calidad, además de otras limitaciones), y por otro lado, evitar los problemas de patentes de Gif por el uso de LZW (algoritmo de compresión patentado por Unisys). Al ver que las limitaciones de gif eran superadas ampliamente por png, la carrera que se inició en 1995 por adoptar este formato ha sido fulgurante.
No obstante, esto no quita que los gifs animados se hayan dejado de utilizar.
Uso de gifs animados en VB 32 bits:
Recordando tiempos pasados… algo de nostalgia.
¿Cómo usábamos gifs animados en VB?.
Me acuerdo cuando delante de Visual Basic 4 32 bits, Visual Basic 5.0 y Visual Basic 6.0 (no de .NET), teníamos en nuestras empresas la necesidad de agregar gifs animados a nuestras aplicaciones.
Por aquel entonces tenía yo mi web en Internet sobre VB y tuve la oportunidad de conocer a una persona que juntos planteamos el problema de los gifs animados y como resolver este problema junto con la problemática de las licencias.
Como en este mundo el miedo es muy nuestro y teníamos auténtico pavor al tema de quebrar una licencia y desconocíamos si podíamos transgredir ese aspecto o no, me pude hacer con un código en C++ de lectura de gif y la estructura del formato de un gif animado (de esto hace ya un montón de años).
Al principio intenté hacer todo en VB, pero no dí con ello, y mis conocimientos de C++ siempre han sido limitados. Con C++ apenas he hecho una aplicación de Windows 3.1, algún pequeño control VBX y OCX, y alguna pequeñísima cosa más, pero poco más… y desde entonces C++ lo he tenido abandonado.
El caso es que pese a esta pequeña frustación, pude contactar con una persona que conocía más que yo C++ y que tenía la misma necesidad que un servidor y que mucha gente en Internet (poder leer un gif animado desde una aplicación de VB), así que a esa persona le pasé todo lo que tenía yo hecho sobre este tema, y concluyó mejor que yo lo que quería abordar.
Creó un control OCX que se hizo muy famoso y cuyo nombre era Marchoso.ocx (seguro que a más de uno le suena).
Ese control lo puse en mis páginas Web (Mundo Visual – Visual Basic inicialmente, y PortalVB.com posteriormente) y corrió como la pólvora por Internet.
Aún hoy día es fácil conseguirlo.
Creo que nunca ha sabido nadie cómo apareció este control ni de donde… y es que el miedo al tema de licenciamiento como decía anteriormente era muy grande.
Han pasado bastante años desde aquello, así que porqué no desvelar ahora esta pequeña historia. Así, alguno que se preguntara de donde venía Marchoso.ocx puede conocer algo más de la aparición del primer control OCX de VB para la lectura de gifs animados. Su creador salvo que quiera hacerlo público no lo revelaré yo, seguirá en el anonimato mientras quiera. 🙂
Conociendo un poco más a Image:
Para poder obtener fácilmente los frames que forman parte de un gif animado, debemos hacer uso del control Image.
El namespace System.Drawing será el utilizado para trabajar con el control Image, sin embargo, también haremos uso de otro namespace, System.Drawing.Imaging.
Y dentro de System.Drawing.Imaging, utilizaremos la clase FrameDimension.
FrameDimension es una clase que no se puede heredar, pero que nos va a permitir interactuar con el control Image para obtener los diferentes frames que constituyen la imagen gif animada.
Gracias a estos dos namespaces, estaremos en disposición de extraer todos y cada uno de los frames que forman parte de un gif animado.
El código:
El siguiente ejemplo muestra de forma práctica como trabajar con el control Image y System.Drawing.Imaging.FrameDimension, y extraer las imágenes o frames que forman parte de un gif animado.
La aplicación de Windows contiene tres controles button y un control pictureBox.
El código de demostración de lo que hemos comentado es el que se indica a continuación:
1: using System;
2: using System.Collections.Generic;
3: using System.Drawing;
4: using System.Windows.Forms;
5:
6: namespace AnimatedGif
7: {
8:
9: public partial class MainForm : Form
10: {
11:
12: public MainForm()
13: {
14: InitializeComponent();
15: } // MainForm
16:
17:
18: private void MainForm_Load(object sender, EventArgs e)
19: {
20: // Indicamos la ruta y la imagen animada.
21: this.Path = @"imagesst_patricks_day.gif";
22: } // MainForm_Load
23:
24: /// <summary>
25: /// Propiedad con la posición máxima (frames) de la imagen.
26: /// </summary>
27: public int MaximunPosition { get; set; }
28:
29: /// <summary>
30: /// Propiedad con la posición de la imagen actual.
31: /// </summary>
32: public int Position { get; set; }
33:
34: /// <summary>
35: /// Ruta en la que se encuentra la imagen gif animada con la que
36: /// trabajaremos.
37: /// </summary>
38: private string Path { get; set; }
39:
40: /// <summary>
41: /// Colección de imágenes que corresponde con los frames del gif
42: /// animado.
43: /// </summary>
44: private List<Image> GifImagesCollection { get; set; }
45:
46: private void btnProcess_Click(object sender, EventArgs e)
47: {
48: // Indicamos la posición inicial (Frame 1).
49: this.Position = 0;
50: // Inicializamos la colección de imágenes o frames de un Gif animado.
51: this.GifImagesCollection = new List<Image>();
52: // Recuperamos y cargamos en memoria la imagen animada.
53: Image image = Image.FromFile(this.Path);
54: // Obtenemos las dimensiones o frames de la imagen.
55: System.Drawing.Imaging.FrameDimension frameDimension = new System.Drawing.Imaging.FrameDimension(image.FrameDimensionsList[0]);
56: int frames = image.GetFrameCount(frameDimension);
57: // Recorremos los frames e insertamos en la colección cada una
58: // de las imágenes.
59: for (int i = 0; i < frames; i++)
60: {
61: // Activamos el frame concreto.
62: image.SelectActiveFrame(frameDimension, i);
63: // Agregamos la imagen a la colección de imágenes.
64: this.GifImagesCollection.Add(new Bitmap(image));
65: }
66: // Indicamos el número máximo de frames.
67: this.MaximunPosition = frames;
68: // Mostramos la primera imagen.
69: ShowImage();
70: } // btnProcess_Click
71:
72: private void btnBack_Click(object sender, EventArgs e)
73: {
74: // Cambiamos la posición de la imagen.
75: this.Position -= 1;
76: // Mostramos la imagen que le corresponde.
77: ShowImage();
78: } // btnBack_Click
79:
80: private void btnNext_Click(object sender, EventArgs e)
81: {
82: // Cambiamos la posición de la imagen.
83: this.Position += 1;
84: // Mostramos la imagen que le corresponde.
85: ShowImage();
86: } // btnNext_Click
87:
88: private void ShowImage()
89: {
90: // Cambiamos la imagen por la que le corresponde.
91: this.pbImage.Image = this.GifImagesCollection[this.Position];
92: // Habilitamos y deshabilitamos los controles para mostrar
93: // la imagen siguiente o anterior.
94: this.btnBack.Enabled = (this.Position == 0 ? false : true);
95: this.btnNext.Enabled = (this.Position == this.MaximunPosition - 1 ? false : true);
96: } // ShowImage
97:
98: } // MainForm
99:
100: } // AnimatedGif
Referencias:
Gif (Graphics Interchange Format).
Gif, Png, problemáticas y soluciones.
Png (Portable Network Graphics).
3 Responsesso far
Habia trabajado con los frames de un tif por temas de ocr y datamatrix pero este ejemplo es realmente util. Muchas gracias
Un saludo.
Muy bueno el ejemplo, igual que el comentario anterior.. lo había usado con multitiff, es muy útil ver que funciona también con gif animados.
Gracias y saludos desde Chile!.
@Carlos, muchas gracias por comentar.
Tuve la oportunidad de trabajar hace ya unos años con escáneres y paso de la información en TIFFs.
Al final tuvimos que adquirir un control Ocx externo para resolver el problema ya que para .NET no había nada, y por otro lado, a nadie se le ocurrió mirar esto nunca.
Como no me gustaría que pasara, pongo en común este tema porque por ahí van justamente los tiros.
Me alegro de que hayas comprendido el fondo del ejemplo, y me alegra que no haya pasado desapercibido por que según veo no eres el único. 🙂
@Jhonny, un fuerte abrazo amigo.
A ver si nos vemos un día de estos, que hace algunos años que no te saludo personalmente.
Muchas gracias a tí también por comentar.
A ver si tienes tiempo y nos sorprendes con alguna mejora o aplicación adicional sobre este tema. 😉
Saludos.