2011-05-09 12 views
11

Quiero agregar una cadena en el medio del bloque de metadatos de la imagen. Bajo algún marcador específico. Tengo que hacerlo a nivel de bytes, ya que .NET no admite campos de metadatos personalizados.Insertar bytes en el medio del archivo binario

El bloque está construido como 1C 02 XX YY YY ZZ ZZ ZZ ... donde XX es el ID del campo que necesito adjuntar y YY YY es su tamaño, ZZ = datos.

Imagino que debería ser más o menos posible leer todos los datos de imagen hasta este marcador (1C 02 XX), luego aumentar los bytes de tamaño (YY YY), agregar datos al final de ZZ y luego agregar el resto del archivo original? ¿Es esto correcto?

¿Cómo debo continuar? Necesita trabajar lo más rápido posible con archivos JPEG de 4-5 MB.

+0

http://www.codeproject.com/KB/GDI-plus/ImageInfo.aspx podría ser útil. –

Respuesta

7

En general, no hay forma de acelerar esta operación. Debe leer al menos la parte que debe moverse y escribirla nuevamente en el archivo actualizado. Crear un nuevo archivo y copiar contenido puede ser más rápido si puede paralelizar las operaciones de lectura y escritura.

Nota: En su caso particular, puede que no sea posible insertar contenido en el medio del archivo ya que la mayoría de los formatos de archivo no están diseñados con tales modificaciones en mente. A menudo hay compensaciones en partes del archivo que no serán válidas cuando se desplaza parte del archivo. Especificar con qué formato de archivo intenta trabajar puede ayudar a otras personas a proporcionar mejores enfoques.

2

resuelto el problema con este código:

  List<byte> dataNew = new List<byte>(); 
      byte[] data = File.ReadAllBytes(jpegFilePath); 

      int j = 0; 
      for (int i = 1; i < data.Length; i++) 
      { 
       if (data[i - 1] == (byte)0x1C) // 1C IPTC 
       { 
        if (data[i] == (byte)0x02) // 02 IPTC 
        { 
         if (data[i + 1] == (byte)fileByte) // IPTC field_number, i.e. 0x78 = IPTC_120 
         { 
          j = i; 
          break; 
         } 
        } 
       } 
      } 

      for (int i = 0; i < j + 2; i++) // add data from file before this field 
       dataNew.Add(data[i]); 

      int countOld = (data[j + 2] & 255) << 8 | (data[j + 3] & 255); // curr field length 
      int countNew = valueToAdd.Length; // new string length 
      int newfullSize = countOld + countNew; // sum 
      byte[] newSize = BitConverter.GetBytes((Int16)newfullSize); // Int16 on 2 bytes (to use 2 bytes as size) 
      Array.Reverse(newSize); // changes order 10 00 to 00 10 
      for (int i = 0; i < newSize.Length; i++) // add changed size 
       dataNew.Add(newSize[i]); 

      for (int i = j + 4; i < j + 4 + countOld; i++) // add old field value 
       dataNew.Add(data[i]); 

      byte[] newString = ASCIIEncoding.ASCII.GetBytes(valueToAdd); 
      for (int i = 0; i < newString.Length; i++) // append with new field value 
       dataNew.Add(newString[i]); 

      for (int i = j + 4 + newfullSize; i < data.Length; i++) // add rest of the file 
       dataNew.Add(data[i]); 

      byte[] finalArray = dataNew.ToArray(); 
      File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(jpegFilePath), "newfile.jpg"), finalArray);     
+1

Tenga cuidado si tiene más 1C 02 bytes en el archivo. Puede envolverlo para buscar solo dentro del segmento 8BIM 04 04. – yosh

+1

No creo que haya ninguna razón para usar MemoryStream ni Image al final de su código, a menos que reestructure sus metadatos de alguna manera? Ya tiene la matriz de bytes que desea, así que simplemente escríbala en la unidad con File.WriteAllBytes (path, finalArray). – PolyTekPatrick

1

Aquí es una solución fácil y bastante rápido. Mueve todos los bytes después del desplazamiento dado a su nueva posición de acuerdo con extraBytes dados, por lo que puede insertar sus datos.

public void ExpandFile(FileStream stream, long offset, int extraBytes) 
{ 
    // http://stackoverflow.com/questions/3033771/file-io-with-streams-best-memory-buffer-size 
    const int SIZE = 4096; 
    var buffer = new byte[SIZE]; 
    var length = stream.Length; 
    // Expand file 
    stream.SetLength(length + extraBytes); 
    var pos = length; 
    int to_read; 
    while (pos > offset) 
    { 
    to_read = pos - SIZE >= offset ? SIZE : (int)(pos - offset); 
    pos -= to_read; 
    stream.Position = pos; 
    stream.Read(buffer, 0, to_read); 
    stream.Position = pos + extraBytes; 
    stream.Write(buffer, 0, to_read); 
    } 

necesitan ser revisados, aunque ...

Cuestiones relacionadas