在 Xamarin c# 中以 .bmp 格式保存裁剪图像

Save a cropped image in .bmp format in Xamarin c#

你好,我是 xamarin 表单的新手,我有一个应用程序可以让你通过相机拍照,然后我给了一个矩形框来裁剪捕获的图像...我已经为 xamarin 编写了代码 android 所有这一切都很好,我最终也可以将图像保存为 JPG 或 PNG。 但我想将最终图像保存为.bmp 文件。

private void SaveOutput(Bitmap croppedImage) {

        if (saveUri != null)
        {
            try
            {
                using var outputStream = ContentResolver.OpenOutputStream(saveUri);
                if (outputStream != null)
                {
                   croppedImage.Compress(Bitmap.CompressFormat.Jpeg, 75, outputStream);
                  
                }
            }

在此函数中,croppedImage 位图被压缩为 jpg。 相反,我想将该位图保存为 .bmp file.i 已经看了很多,但还没有找到任何解决方案。 有人可以建议我能做什么吗?

这是一个与原生 Android 类似的 issue 。您可以将解决方案转换为 C#,如下所示

public class AndroidBmpUtil
{
    private readonly int BMP_WIDTH_OF_TIMES = 4;
    private readonly int BYTE_PER_PIXEL = 3;

    /**
     * Android Bitmap Object to Window's v3 24bit Bmp Format File
     * @param orgBitmap
     * @param filePath
     * @return file saved result
     */

    public bool Save(Bitmap orgBitmap, string filePath)
    {
        if (orgBitmap == null)
        {
            return false;
        }

        if (filePath == null)
        {
            return false;
        }

        var isSaveSuccess = true;

        //image size
        var width = orgBitmap.Width;
        var height = orgBitmap.Height;

        //image dummy data size
        //reason : bmp file's width equals 4's multiple
        var dummySize = 0;
        byte[] dummyBytesPerRow = null;
        var hasDummy = false;
        if (isBmpWidth4Times(width))
        {
            hasDummy = true;
            dummySize = BMP_WIDTH_OF_TIMES - width%BMP_WIDTH_OF_TIMES;
            dummyBytesPerRow = new byte[dummySize*BYTE_PER_PIXEL];
            for (var i = 0; i < dummyBytesPerRow.Length; i++)
            {
                dummyBytesPerRow[i] = 0xFF;
            }
        }

        var pixels = new int[width*height];
        var imageSize = pixels.Length*BYTE_PER_PIXEL + height*dummySize*BYTE_PER_PIXEL;
        var imageDataOffset = 0x36;
        var fileSize = imageSize + imageDataOffset;

        //Android Bitmap Image Data
        orgBitmap.GetPixels(pixels, 0, width, 0, 0, width, height);

        //ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
        var buffer = ByteBuffer.Allocate(fileSize);

        try
        {
            /**
             * BITMAP FILE HEADER Write Start
             **/
            buffer.Put(0x42);
            buffer.Put(0x4D);

            //size
            buffer.Put(WriteInt(fileSize));

            //reserved
            buffer.Put(WriteShort(0));
            buffer.Put(WriteShort(0));

            //image data start offset
            buffer.Put(WriteInt(imageDataOffset));

            /** BITMAP FILE HEADER Write End */

            //*******************************************

            /** BITMAP INFO HEADER Write Start */
            //size
            buffer.Put(WriteInt(0x28));

            //width, height
            buffer.Put(WriteInt(width));
            buffer.Put(WriteInt(height));

            //planes
            buffer.Put(WriteShort(1));

            //bit count
            buffer.Put(WriteShort(24));

            //bit compression
            buffer.Put(WriteInt(0));

            //image data size
            buffer.Put(WriteInt(imageSize));

            //horizontal resolution in pixels per meter
            buffer.Put(WriteInt(0));

            //vertical resolution in pixels per meter (unreliable)
            buffer.Put(WriteInt(0));

            buffer.Put(WriteInt(0));

            buffer.Put(WriteInt(0));

            /** BITMAP INFO HEADER Write End */

            var row = height;
            var col = width;
            var startPosition = 0;
            var endPosition = 0;

            while (row > 0)
            {
                startPosition = (row - 1)*col;
                endPosition = row*col;

                for (var i = startPosition; i < endPosition; i++)
                {
                    buffer.Put(Write24BitForPixcel(pixels[i]));

                    if (hasDummy)
                    {
                        if (isBitmapWidthLastPixcel(width, i))
                        {
                            buffer.Put(dummyBytesPerRow);
                        }
                    }
                }
                row--;
            }

            var fos = new FileOutputStream(filePath);
            fos.Write(new byte[buffer.Remaining()]);
            fos.Close();
        }
        catch (Exception e1)
        {
            isSaveSuccess = false;
        }
        finally
        {
        }

        return isSaveSuccess;
    }

    /**
     * Is last pixel in Android Bitmap width  
     * @param width
     * @param i
     * @return
     */

    private bool isBitmapWidthLastPixcel(int width, int i)
    {
        return i > 0 && i%(width - 1) == 0;
    }

    /**
     * BMP file is a multiples of 4?
     * @param width
     * @return
     */

    private bool isBmpWidth4Times(int width)
    {
        return width%BMP_WIDTH_OF_TIMES > 0;
    }

    /**
     * Write integer to little-endian 
     * @param value
     * @return
     * @throws IOException
     */

    private byte[] WriteInt(int value)
    {
        var b = new byte[4];

        b[0] = (byte) (value & 0x000000FF);
        b[1] = (byte) ((value & 0x0000FF00) >> 8);
        b[2] = (byte) ((value & 0x00FF0000) >> 16);
        b[3] = (byte) ((value & 0xFF000000) >> 24);

        return b;
    }

    /**
     * Write integer pixel to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */

    private byte[] Write24BitForPixcel(int value)
    {
        var
            b = new byte[3];

        b[0] = (byte) (value & 0x000000FF);
        b[1] = (byte) ((value & 0x0000FF00) >> 8);
        b[2] = (byte) ((value & 0x00FF0000) >> 16);

        return b;
    }

    /**
     * Write short to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */

    private byte[] WriteShort(short value)
    {
        var
            b = new byte[2];

        b[0] = (byte) (value & 0x00FF);
        b[1] = (byte) ((value & 0xFF00) >> 8);

        return b;
    }
}