views:

674

answers:

3

I'm using C# in ASP.NET version 2. I'm trying to open an image file, read (and change) the XMP header, and close it back up again. I can't upgrade ASP, so WIC is out, and I just can't figure out how to get this working.

Here's what I have so far:

Bitmap bmp = new Bitmap(Server.MapPath(imageFile));

MemoryStream ms = new MemoryStream();

StreamReader sr = new StreamReader(Server.MapPath(imageFile));

*[stuff with find and replace here]*

byte[] data = ToByteArray(sr.ReadToEnd());

ms = new MemoryStream(data);

originalImage = System.Drawing.Image.FromStream(ms);

Any suggestions?

A: 

You can use the following functions to read/write the binary data:

    public byte[] GetBinaryData(string path, int bufferSize)
    {
        MemoryStream ms = new MemoryStream();
        using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
        {
            int bytesRead;
            byte[] buffer = new byte[bufferSize];
            while((bytesRead = fs.Read(buffer,0,bufferSize))>0)
            {
                ms.Write(buffer,0,bytesRead);
            }
        }
        return(ms.ToArray());
    }

    public void SaveBinaryData(string path, byte[] data, int bufferSize)
    {
        using (FileStream fs = File.Open(path, FileMode.Create, FileAccess.Write))
        {
            int totalBytesSaved = 0;
            while (totalBytesSaved<data.Length)
            {
                int remainingBytes = Math.Min(bufferSize, data.Length - totalBytesSaved);
                fs.Write(data, totalBytesSaved, remainingBytes);
                totalBytesSaved += remainingBytes;
            }
        }
    }

However, loading entire images to memory would use quite a bit of RAM. I don't know much about XMP headers, but if possible you should:

  • Load only the headers in memory
  • Manipulate the headers in memory
  • Write the headers to a new file
  • Copy the remaining data from the original file
Badaro
+1  A: 
Chris
A: 

Part 3 of the XMP spec, page 13 specifically talks about how to edit a file in place without needing to understand the surrounding format (although they do suggest this as a last resort). The embedded XMP packet looks like this:

<?xpacket begin="■" id="W5M0MpCehiHzreSzNTczkc9d"?>
    ... the serialized XMP as described above: ...
    <x:xmpmeta xmlns:x="adobe:ns:meta/">
    <rdf:RDF xmlns:rdf= ...>
        ...
    </rdf:RDF>
    </x:xmpmeta>
    ... XML whitespace as padding ...
<?xpacket end="w"?>

In this example, ‘■’ represents the Unicode “zero width non-breaking space character” (U+FEFF) used as a byte-order marker.

That section also gives specific byte patterns to look for when scanning the bytes. This would complement Chris' answer about reading the file in as a giant byte stream.

McKAMEY