Vamos a programar #19 - Extraer una imagen embebida en un MP3 - ArtView

El día de hoy vamos a terminar (ahora si no es broma) el código para extraer las imágenes que se encuentran embebidas en los archivos MP3.


En el post anterior implementamos algunas partes del código y lo pasamos a funciones, antes de avanzar hay algo que quiero decir de una de las funciones anteriores. Una persona que visitó el blog me dijo que la función DataToAlbum no funcionaba bien, a pesar de que yo mostré imágenes en la que parecía que todo funcionaba bien, pero no era asi, al analizar todos los bytes que componían al string (solo la versión unicode), había un carácter no visible. El carácter es 0xFF, eso se debia a que también le pasábamos a la función GetString los bytes adicionales que se usan para indicar que se trata de un string unicote, para agregarlo, solo hay que movernos hasta el tercer byte. Recordemos que la función que hicimos recibía cómo parámetro una matriz de bytes donde el primero, era el byte que nos indicaba cual era el tipo de codificación; uno para unicode y cero para ASCII. En el caso de la codificacion ASCII no existía mayor problema porque seguido de ese byte, inmediatamente va lo que vendría siendo el string en sí, pero en el caso del string unicode, inmediatamente después del primer byte, siguen dos bytes que sirven para indicar que tipo de codificación se usa (en lectores de texto por ejemplo,0xFF 0xFE para unicode).

private string DataToAlbum(byte[] Data)
{
 if (Data[0] == 0)
  return Encoding.ASCII.GetString(Data,1,Data.Length-1).TrimEnd((char)0).TrimStart((char)0);
 if (Data[0] == 1)
  return Encoding.Unicode.GetString(Data,3,Data.Length-3).TrimEnd((char)0).TrimStart((char)0);
 else
  return "Desconocido";
}

Procesando por lotes.

El chiste de todo esto era extraer las imágenes debido a que cuando se convertían entre una versión a otra, por lo que me dijeron, algunos programas omiten la imagen, entonces lo ideal es extraer primero la imagen y después insertarla de nuevo, eso si, solo después de haber realizado la conversión a la versión de destino.

Para eso creamos la función BatchProcess cuyo código es el siguiente:

private void BatchProccess(List<string> Files, string SaveFolder)
{
 int Current = 0;
 PBProgress.Maximum = Files.Count;
 Thread DoWork = new Thread (new ThreadStart(() =>
 {
  foreach (string Item in Files)
  {
   ImageContent(Item,SaveFolder);
   Current = Current + 1;
   UpdateProgress(Current);
   if (Current == Files.Count) {
    IsWorking =false;
   }
  }
 }
 ));
 DoWork.Start();
}


Está función recibe cómo parámetros una lista del tipo string que contiene todos los archivo de los cuales queremos extraerles la imágenes, el otro parámetro es un string que contiene la ruta (fólder) en donde guardáremos las imágenes. Después creamos un thread para no bloquear la interfaz principal. De hecho cuando pruebes el código, al agregar los archivos, si agregas muchos, notarás que la aplicación se congela un poco (dependiendo de cuantos agregues y de que tan potente sea tu equipo), esto lo deje así para que notes la diferenta entre usar un thread aparte y cuando no.
El uso del thread (hilo a partir de este momento). Para esta aplicación es realmente sencillo, ya que no hacemos uso de las funciones para controlarla como es debido, de hecho para saber si aun sigue ocupado ese hilo usamos el flag IsWorking. Para poder saber el progreso del proceso usamos un delegado que se encargara de recibir el valor actual del progreso, después llamará a la funcion UpdateProgress que se encargará de actualizar la propiedad Value del ProgressBar.

El código de la funcion UpdateProgress (incluido el delegado) es el siguiente:

private delegate void UpdateProgressDelegate(int Value);

private void UpdateProgress(int Value)
{
 if (PBProgress.InvokeRequired)
 {
  PBProgress.Invoke(new UpdateProgressDelegate(UpdateProgress), Value);
 }
 else
 {
  PBProgress.Value = Value;
 }
}

El uso un poco más avanzado de los hilos lo veremos en el siguiente Post.
Y ya solo que da el código que se encargará de hacer el trabajo. El uso de un flag para determinar si hay o no un proceso es importante, ya que podemos cerrar la ventana principal y algun proceso todavía se puede estar ejecutando, suponiendo que eres cómo yo y rara vez le pide a Windows que te dé permiso para sacar tu dispositivo, si lo extraes en medio de un proceso de lectura/escritura, puede ser que se dañe tu USB.

El código completo lo puedes descargar aquí, Dudas o comentarios no dudes en decirlo. Antes de terminar quiero agradecer al que reportó el error, preferiría que no usaran perfiles anónimos para poder dar el reconocimiento que se debe.

Por ahora es todo, los leo luego.
P.D, “Arceus existe ;)”

4 comentarios