1

simple question that I simply can't seem to find a decent answer for.

i'm trying to convert a memory image to a byte array in order to upload it as a Base64String

Bitmap CapSc()
{
    using(Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
    {
       using(Graphics g = Graphics.FromImage(bitmap))
       {
         g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
       }
       return bitmap;
    }
}

Image toUpload;
toUpload = (Image)CapSc();

public static byte[] GetBytesFromImage(Image img)
    {
        if (img == null) return null;
        using (MemoryStream stream = new MemoryStream())
        {
            img.Save(stream, img.RawFormat);
            return stream.ToArray();
        }
    }

GetBytesFromImage(toUpload);

however the 'img.Save' constantly returns errors where it seems to require a third paramater of EncoderParamaters, no sample code or developer solutions on MSDN say this is neccessary but it constantly returns errors if i have it present or not.

the specific error is 'Paramter cannot be null. Paramater name: encoder'

any help would be much appreciated.

colsw
  • 3,216
  • 1
  • 14
  • 28
  • 1
    What `Image` type is this? There are various different ones across different frameworks... – Jon Skeet Oct 17 '14 at 14:59
  • System.Drawing.Image, returned originally as bitmap and cast. – colsw Oct 17 '14 at 15:00
  • possible duplicate of [C# Image to Byte\[\] and Byte\[\] to Image](http://stackoverflow.com/questions/8764280/c-sharp-image-to-byte-and-byte-to-image) – Sergey Malyutin Oct 17 '14 at 15:01
  • Note that you shouldn't use `stream.GetBuffer()` even if `Save` succeeds - you should use `ToArray`. The buffer will be larger than the data requires (usually). – Jon Skeet Oct 17 '14 at 15:01
  • i've tried using the solutions in that answer as well as multiple others, they all give similar errors of requiring the additional paramater. – colsw Oct 17 '14 at 15:02
  • thanks for the heads up on ToArray, i've changed it. – colsw Oct 17 '14 at 15:03
  • Can you share the code of creating the img object? – Sergey Malyutin Oct 17 '14 at 15:08
  • I have multiple versions of CapSc for different reasons, this is more of a test one, but is the one i've been using for the above errors. (added to OP) – colsw Oct 17 '14 at 15:15
  • Is this a compile-time error or a runtime error? Looks like runtime. Just confirming. – Tim Oct 17 '14 at 15:17
  • try changing `img.RawFormat` to `ImageFormat.Jpg` - it is wanting an encoder for whatever underlying format thats in – Ňɏssa Pøngjǣrdenlarp Oct 17 '14 at 15:19
  • its a runtime error yes, I have tried PNG and jpeg with previous attempts, I'll try it now with this. – colsw Oct 17 '14 at 15:31
  • on mine, the initial `ImageFormat` reported by RawFormat for a scrncap is an odd GUID key (undefined? internal?); using `ImageFormat.Jpg` saves fine and easier than getting an encoder unless you need to set some special settings or use a specific format. – Ňɏssa Pøngjǣrdenlarp Oct 17 '14 at 15:38

2 Answers2

1

Inside of your Image.Save call (where you don't specify an encoder), the framework is making this call:

ImageCodecInfo encoder = format.FindEncoder();

and then passing that result into the overload that does specify an encoder.

What's happening is that FindEncoder is returning null in your case. So the system can't find an encoder that works for whatever ImageFormat is specified by the RawFormat property.

To see what Codecs are available on your machine, you could iterate through the result of

ImageCodeInfo.GetImageEncoders()

Or you could just go with one you know is there like jpeg :)

Tim
  • 14,999
  • 1
  • 45
  • 68
  • `RawFormat` is a property of type `ImageFormat` not an actual format. The problem is that whatever format it is in, it cant find an encoder for it. – Ňɏssa Pøngjǣrdenlarp Oct 17 '14 at 15:26
  • That's what I meant, but looking at what I wrote that wasn't at all obvious. Thanks for pointing it out. – Tim Oct 17 '14 at 15:29
1

This is pretty much exactly what I've been working on the past month. Provided I didn't miss anything, this should work (you may need an extra using statement or two):

ImageCodecInfo codec;
EncoderParameters myEPS;

public YourConstructor() {

    codec = GetEncoder(ImageFormat.Jpeg);
    myEPS = new EncoderParameters(1);
    System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
    EncoderParameter myEP = new EncoderParameter(myEncoder, 60L); // 0-100 quality level
    myEPS.Param[0] = myEP;

}

private ImageCodecInfo GetEncoder(ImageFormat format)
{
    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();

    foreach (ImageCodecInfo codec in codecs)
    {
        if (codec.FormatID == format.Guid)
        {
            return codec;
        }
    }
    return null;
}

public static byte[] GetBytesFromImage(Image img)
{
    if (img == null) return null;
    using (MemoryStream stream = new MemoryStream())
    {
        img.Save(stream, codec, myEPS);
        return stream.ToArray();
    }
}
Russell Uhl
  • 4,181
  • 2
  • 18
  • 28