Search code examples
c#.net-6.0protobuf-net

How to handle System.Drawing.Image stored with protobuf just like a byte array?


I'm using protobuf-net v2.4.0 for storing System.Drawing.Image with the below surrogates:

internal class SystemDrawingImageSurrogate
{
    public SystemDrawingImageSurrogate(byte[] data)
    {
        Data = data;            
    }

    public byte[] Data;

    public static implicit operator System.Drawing.Image(SystemDrawingImageSurrogate surrogate)
    {
        if (surrogate == null || surrogate.Data == null)
            return null;

        MemoryStream stream = new MemoryStream(surrogate.Data);
        var bitmap = new System.Drawing.Bitmap(stream);
        return bitmap;
    }

    public static implicit operator SystemDrawingImageSurrogate(System.Drawing.Image source)
    {
        if (source == null)
            return null;

        byte[] byteImage = (byte[])new ImageConverter().ConvertTo(source, typeof(byte[]));            
        return new SystemDrawingImageSurrogate(byteImage);            
    }
}

And I use it to store classes like the below ones:

public class PersonWithPhotoSurrogate : PersonSurrogate
{        
    public PersonWithPhotoSurrogate(PersonWithPhoto pwp) : base(pwp)
    {

    }

    public int PictureWidth;

    public int PictureHeight;

    
    public System.Drawing.Image Photo;
}

public class FileBodySurrogate
{
    public FileBodySurrogate(FileBody fileBody) { }

    public List<Person> People;
}

Now I need to move from net-framework to net6, so I need to declare the PersonWithPhotoSurrogate.Photo field as byte[] instead of Image as shown below:

public class PersonWithPhotoSurrogate : PersonSurrogate
{        
    public PersonWithPhotoSurrogate(PersonWithPhoto pwp) : base(pwp)
    {

    }

    public int PictureWidth;

    public int PictureHeight;

    
    public /*System.Drawing.Image*/ byte[] Photo;
}

How can I handle this to preserve backward compatibility when reading old files stored?


Solution

  • Your SystemDrawingImageSurrogate adds an extra layer into the model, so if you're switching from Image to simply byte[], you'll still need to represent that layer; perhaps (untested):

    public class PersonWithPhotoSurrogate : PersonSurrogate
    {        
        public PersonWithPhotoSurrogate(PersonWithPhoto pwp) : base(pwp)
        {
    
        }
    
        public int PictureWidth;
    
        public int PictureHeight;
    
        
        public ImageWrapper Photo;
    }
    
    public class ImageWrapper
    {
        public byte[] Data;
    }
    

    obviously with the same tag numbers as were in the original model. You shouldn't need the surrogate pieces - you just need the model to look the same as it would have with the surrogate.