简体   繁体   中英

Attempting to save a picture in C# to a Byte Array using Canvas Bitmap but it only ever outputs exactly 2^16 bytes

I am attempting to make a Universal Windows Platform app in C# and I have spent the last week mostly on attempting to get a byte array of a Canvas Bitmap object. At first I thought I could use the Canvas Bitmap function byteArray = pictureBitmap.GetPixelBytes where pictureBitmap is the Canvas Bitmap object that has a loaded image in it.

I did some debugging and am pretty sure pictureBitmap has an image saved in it as a Canvas Bitmap type, however, trying to get the image into a Byte[] is a real challenge and GetPixelBytes does not return the header information and only outputs a.bmp so I can't really use that.

After that I tried implementing my own IRandomAccessStream interface as well as following along with a tutorial, however, no matter what the following code only outputs exactly 2^16 bytes on the second debug output, not the whole image.

        using (var randomStream = new ImageStream(1000000)) 
        {
            Debug.WriteLine("randomStream Initial Length: " + randomStream.Size);
            await pictureBitmap.SaveAsync(randomStream, CanvasBitmapFileFormat.Jpeg, 0.8f);
            Debug.WriteLine("randomStream After Length: " + randomStream.Size);
        }

For the implementation of the IRandomAccessStream interface I tried both Stream and MemoryStream although both only output a 65536 bytes. Any help is greatly appreciated, thanks.

EDIT

This is my code for the ImageStream class which implements the interface IRandomAcessStream. If I had to guess where the problem is I believe it could either be in FlushAsync() , ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) , or Seek(ulong position) . I know that when I save the image to a file it is the correct size and format, it is just when saving to a Stream that I seem to have trouble.

class ImageStream : IRandomAccessStream
{
    private MemoryStream internalImageStream;

    public ImageStream()
    {
        internalImageStream = new MemoryStream();
    }
    public ImageStream(int size)
    {
        internalImageStream = new MemoryStream(size);
    }

    public byte[] ConvertToArray()
    {
        return this.internalImageStream.ToArray();
    }

    public int Capacity
    {
        get { return this.internalImageStream.Capacity; }
        set { this.internalImageStream.Capacity = (int)value; }
    }

    public bool CanRead
    {
        get { return true; }
    }

    public bool CanWrite
    {
        get { return true; }
    }

    public ulong Position
    {
        get { return (ulong)this.internalImageStream.Position; }
        set { this.internalImageStream.Position = (long)value; }
    }

    public ulong Size
    {
        get { return (ulong)this.internalImageStream.Length; }
        set { this.internalImageStream.SetLength((long)value); }
    }

    public IRandomAccessStream CloneStream()
    {
        ImageStream newImageStream = new ImageStream();
        newImageStream.internalImageStream = this.internalImageStream;
        return newImageStream;
    }

    public void Dispose()
    {
        this.internalImageStream.Dispose();
    }

    public IAsyncOperation<bool> FlushAsync()
    {
        var outputStream = this.GetOutputStreamAt(0);
        return outputStream.FlushAsync();
    }

    public IInputStream GetInputStreamAt(ulong position)
    {
        this.internalImageStream.Seek((long)position, SeekOrigin.Begin);

        return this.internalImageStream.AsInputStream();
    }

    public IOutputStream GetOutputStreamAt(ulong position)
    {
        this.internalImageStream.Seek((long)position, SeekOrigin.Begin);

        return this.internalImageStream.AsOutputStream();
    }

    public void Seek(ulong position)
    {
        this.internalImageStream.Seek((long)position, 0);
    }

    public IAsyncOperationWithProgress<IBuffer,uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {
        var inputStream = this.GetInputStreamAt(0);
        return inputStream.ReadAsync(buffer, count, options);
    }

    public IAsyncOperationWithProgress<uint,uint> WriteAsync(IBuffer buffer)
    {
        var outputStream = this.GetOutputStreamAt(0);
        return outputStream.WriteAsync(buffer);
    }
}

The problem appears in the ImageStream.WriteAsync method.

This method will be called multiple times during stream writing (just like moving things, you need to move several times if you can't move at one time). But in this method, you always write from 0, which means that when you write the second time, it will overwrite the previous data.

Try this:

public IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer)
{
    var outputStream = this.GetOutputStreamAt(this.Size);
    return outputStream.WriteAsync(buffer);
}

This can ensure that the call will continue to write from the place where it last ended, and you will get the correct result.

Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM