Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android : save a Bitmap to bmp file format

I have a Bitmap in memory and I need to save it in a bmp file (using the bmp file format).

Is there any way to do it on Android ?

(I read a lot of post suggesting to use the png format - which is loss-less - but, that's not what I need: I really need the bmp format).

I already have some code to save it in jpeg or png using the Bitmap.compress method :

/**
 * Save data to file using format.
 * When format is null : the bitmap will be saved in bmp format
 **/

public void writeBitmapToFile(Bitmap data, File file, Bitmap.CompressFormat format) {
    FileOutputStream os = null;
    try {
        os = new FileOutputStream(file);
        if(format==null){

            //TODO : write data to file using the bmp format

        }else{
            data.compress(format, 100, os); //ok for JPEG and PNG
        }
        os.flush();
    } catch (Exception e) {
        //irrelevant code
    } finally {
        //irrelevant code
    }
}
like image 999
ben75 Avatar asked Apr 07 '14 10:04

ben75


4 Answers

Unfortunately, the answers above didn't fully work for grayscale images, in my case. Not sure why.

That's why I wrote this one (Additionally I'm using a ByteBuffer, because of the performance):

import android.graphics.Bitmap;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;

public class BmpFile {
    // Private constants
    private final static int BITMAPFILEHEADER_SIZE = 14;
    private final static int BITMAPINFOHEADER_SIZE = 40;
    // Private variable declaration
    // Bitmap file header
    private byte bitmapFileHeader[] = new byte[14];
    private byte bfType[] = {'B', 'M'};
    private int bfSize = 0;
    private int bfReserved1 = 0;
    private int bfReserved2 = 0;
    private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;
    // Bitmap info header
    private byte bitmapInfoHeader[] = new byte[40];
    private int biSize = BITMAPINFOHEADER_SIZE;
    private int biWidth = 0;
    private int biHeight = 0;
    private int biPlanes = 1;
    private int biBitCount = 24;
    private int biCompression = 0;
    private int biSizeImage = 0x030000;
    private int biXPelsPerMeter = 0x0;
    private int biYPelsPerMeter = 0x0;
    private int biClrUsed = 0;
    private int biClrImportant = 0;
    // Bitmap raw data
    private int pixels[];
    // File section
    private ByteBuffer buffer = null;
    private OutputStream outputStream;

    // Default constructor
    public BmpFile() {
    }

    public void saveBitmap(
        String parFilename,
        Bitmap bitmap
    ) {
        try {
            outputStream = new FileOutputStream(parFilename);
            save(bitmap);
            outputStream.close();
        } catch (Exception e) {
            Log.e("Exception", e.getMessage());
        }
    }

    public void saveBitmap(
        Bitmap bitmap,
        OutputStream outputStream
    ) {
        this.outputStream = outputStream;
        save(bitmap);
    }

    /*
     *  The saveMethod is the main method of the process. This method
     *  will call the convertImage method to convert the memory image to
     *  a byte array; method writeBitmapFileHeader creates and writes
     *  the bitmap file header; writeBitmapInfoHeader creates the
     *  information header; and writeBitmap writes the image.
     */
    private void save(
        Bitmap bitmap
    ) {
        try {
            convertImage(bitmap);
            writeBitmapFileHeader();
            writeBitmapInfoHeader();
            writeBitmap();
            // write to output stream
            outputStream.write(buffer.array());
        } catch (Exception e) {
            Log.e("Exception", e.getMessage());
        }
    }

    /*
     * convertImage converts the memory image to the bitmap format (BRG).
     * It also computes some information for the bitmap info header.
     */
    private boolean convertImage(
        Bitmap bitmap
    ) {
        int pad;
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        pixels = new int[width * height];

        bitmap.getPixels(
            pixels,
            0,
            width,
            0,
            0,
            width,
            height);

        pad = (4 - ((width * 3) % 4)) * height;
        biSizeImage = ((width * height) * 3) + pad;
        bfSize = biSizeImage + BITMAPFILEHEADER_SIZE +
            BITMAPINFOHEADER_SIZE;

        buffer = ByteBuffer.allocate(bfSize);
        biWidth = width;
        biHeight = height;
        return (true);
    }

    /*
     * writeBitmap converts the image returned from the pixel grabber to
     * the format required. Remember: scan lines are inverted in
     * a bitmap file!
     * Each scan line must be padded to an even 4-byte boundary.
     */
    private void writeBitmap() {
        int size;
        int value;
        int j;
        int i;
        int rowCount;
        int rowIndex;
        int lastRowIndex;
        int pad;
        int padCount;
        byte rgb[] = new byte[3];
        size = (biWidth * biHeight) - 1;
        pad = 4 - ((biWidth * 3) % 4);
        if (pad == 4)   // Bug correction
            pad = 0;    // Bug correction
        rowCount = 1;
        padCount = 0;
        rowIndex = size - biWidth;
        lastRowIndex = rowIndex;
        try {
            for (j = 0; j < size; j++) {
                value = pixels[rowIndex];
                rgb[0] = (byte) (value & 0xFF);
                rgb[1] = (byte) ((value >> 8) & 0xFF);
                rgb[2] = (byte) ((value >> 16) & 0xFF);
                buffer.put(rgb);
                if (rowCount == biWidth) {
                    padCount += pad;
                    for (i = 1; i <= pad; i++) {
                        buffer.put((byte) 0x00);
                    }
                    rowCount = 1;
                    rowIndex = lastRowIndex - biWidth;
                    lastRowIndex = rowIndex;
                } else
                    rowCount++;
                rowIndex++;
            }
            // Update the size of the file
            bfSize += padCount - pad;
            biSizeImage += padCount - pad;
        } catch (Exception e) {
            Log.e("Exception", e.getMessage());
        }
    }

    /*
     * writeBitmapFileHeader writes the bitmap file header to the file.
     */
    private void writeBitmapFileHeader() {
        try {
            buffer.put(bfType);
            buffer.put(intToDWord(bfSize));
            buffer.put(intToWord(bfReserved1));
            buffer.put(intToWord(bfReserved2));
            buffer.put(intToDWord(bfOffBits));
        } catch (Exception e) {
            Log.e("Exception", e.getMessage());
        }
    }

    /*
     * writeBitmapInfoHeader writes the bitmap information header
     * to the file.
     */
    private void writeBitmapInfoHeader() {
        try {
            buffer.put(intToDWord(biSize));
            buffer.put(intToDWord(biWidth));
            buffer.put(intToDWord(biHeight));
            buffer.put(intToWord(biPlanes));
            buffer.put(intToWord(biBitCount));
            buffer.put(intToDWord(biCompression));
            buffer.put(intToDWord(biSizeImage));
            buffer.put(intToDWord(biXPelsPerMeter));
            buffer.put(intToDWord(biYPelsPerMeter));
            buffer.put(intToDWord(biClrUsed));
            buffer.put(intToDWord(biClrImportant));
        } catch (Exception e) {
            Log.e("Exception", e.getMessage());
        }
    }

    /*
     * intToWord converts an int to a word, where the return
     * value is stored in a 2-byte array.
     */
    private byte[] intToWord(
        int parValue
    ) {
        byte retValue[] = new byte[2];
        retValue[0] = (byte) (parValue & 0x00FF);
        retValue[1] = (byte) ((parValue >> 8) & 0x00FF);
        return (retValue);
    }

    /*
     * intToDWord converts an int to a double word, where the return
     * value is stored in a 4-byte array.
     */
    private byte[] intToDWord(
        int parValue
    ) {
        byte retValue[] = new byte[4];
        retValue[0] = (byte) (parValue & 0x00FF);
        retValue[1] = (byte) ((parValue >> 8) & 0x000000FF);
        retValue[2] = (byte) ((parValue >> 16) & 0x000000FF);
        retValue[3] = (byte) ((parValue >> 24) & 0x000000FF);
        return (retValue);
    }
}
like image 91
Manuel Schmitzberger Avatar answered Oct 26 '22 23:10

Manuel Schmitzberger


(I'm answering my own question)

Here is my current solution. It is derived from this source : https://github.com/ultrakain/AndroidBitmapUtil (thanks to ultrakain and @Francescoverheye )

I just fix a little bug in computation of the dummy bytes that must be added to each row (so that the length of each row in bytes is a multiple of 4 (as required by the bmp format specifications).

I also made some changes to improve the performances.

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import android.graphics.Bitmap;
import android.util.Log;

public class AndroidBmpUtil {

    private static final int BMP_WIDTH_OF_TIMES = 4;
    private static final 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 static boolean save(Bitmap orgBitmap, String filePath) throws IOException {
        long start = System.currentTimeMillis();
        if(orgBitmap == null){
            return false;
        }

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

        boolean isSaveSuccess = true;

        //image size
        int width = orgBitmap.getWidth();
        int height = orgBitmap.getHeight();

        //image dummy data size
        //reason : the amount of bytes per image row must be a multiple of 4 (requirements of bmp format)
        byte[] dummyBytesPerRow = null;
        boolean hasDummy = false;
        int rowWidthInBytes = BYTE_PER_PIXEL * width; //source image width * number of bytes to encode one pixel.
        if(rowWidthInBytes%BMP_WIDTH_OF_TIMES>0){
            hasDummy=true;
            //the number of dummy bytes we need to add on each row
            dummyBytesPerRow = new byte[(BMP_WIDTH_OF_TIMES-(rowWidthInBytes%BMP_WIDTH_OF_TIMES))];
            //just fill an array with the dummy bytes we need to append at the end of each row
            for(int i = 0; i < dummyBytesPerRow.length; i++){
                dummyBytesPerRow[i] = (byte)0xFF;
            }
        }

        //an array to receive the pixels from the source image
        int[] pixels = new int[width * height];

        //the number of bytes used in the file to store raw image data (excluding file headers)
        int imageSize = (rowWidthInBytes+(hasDummy?dummyBytesPerRow.length:0)) * height;
        //file headers size
        int imageDataOffset = 0x36; 

        //final size of the file
        int fileSize = imageSize + imageDataOffset;

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

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

        /**
         * BITMAP FILE HEADER Write Start
         **/
        buffer.put((byte)0x42);
        buffer.put((byte)0x4D);

        //size
        buffer.put(writeInt(fileSize));

        //reserved
        buffer.put(writeShort((short)0));
        buffer.put(writeShort((short)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
        //if we add 3 dummy bytes per row : it means we add a pixel (and the image width is modified.
        buffer.put(writeInt(width+(hasDummy?(dummyBytesPerRow.length==3?1:0):0)));
        buffer.put(writeInt(height));

        //planes
        buffer.put(writeShort((short)1));

        //bit count
        buffer.put(writeShort((short)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 */

        int row = height;
        int col = width;
        int startPosition = (row - 1) * col;
        int endPosition = row * col;
        while( row > 0 ){
            for(int i = startPosition; i < endPosition; i++ ){
                buffer.put((byte)(pixels[i] & 0x000000FF));
                buffer.put((byte)((pixels[i] & 0x0000FF00) >> 8));
                buffer.put((byte)((pixels[i] & 0x00FF0000) >> 16));
            }
            if(hasDummy){
                buffer.put(dummyBytesPerRow);
            }
            row--;
            endPosition = startPosition;
            startPosition = startPosition - col;
        }

        FileOutputStream fos = new FileOutputStream(filePath);
        fos.write(buffer.array());
        fos.close();
        Log.v("AndroidBmpUtil" ,System.currentTimeMillis()-start+" ms");

        return isSaveSuccess;
    }

    /**
     * Write integer to little-endian
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeInt(int value) throws IOException {
        byte[] 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 short to little-endian byte array
     * @param value
     * @return
     * @throws IOException
     */
    private static byte[] writeShort(short value) throws IOException {
        byte[] b = new byte[2];

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

        return b;
    }
}
like image 36
ben75 Avatar answered Oct 27 '22 00:10

ben75


Code to convert android Bitmap object to 8bit bmp file. It is derived from this C# project : https://www.codeproject.com/articles/70442/c-rgb-to-palette-based-bit-greyscale-bitmap-clas

import android.graphics.Bitmap;
import android.graphics.Color;


public class BitmapConvertor {

    private  byte[] Color_palette = new byte[1024]; //a palette containing 256 colors
   private   byte[] BMP_File_Header = new byte[14];
   private  byte[] DIB_header = new byte[40];
  private   byte[] Bitmap_Data = null;


    //returns a byte array of a grey scale bitmap image
    public    byte[] CreateGrayBitmapArray(Bitmap Image) {
        try {
            create_parts(Image);
            //Create the array
            byte[] bitmap_array = new byte[BMP_File_Header.length + DIB_header.length
                    + Color_palette.length + Bitmap_Data.length];
            Copy_to_Index(bitmap_array, BMP_File_Header, 0);
            Copy_to_Index(bitmap_array, DIB_header, BMP_File_Header.length);
            Copy_to_Index(bitmap_array, Color_palette, BMP_File_Header.length + DIB_header.length);
            Copy_to_Index(bitmap_array, Bitmap_Data, BMP_File_Header.length + DIB_header.length + Color_palette.length);

            return bitmap_array;
        } catch (Exception e) {
            return null; //return a null single byte array if fails
        }
    }


    //creates byte array of 256 color grayscale palette
    private   byte[] create_palette() {
        byte[] color_palette = new byte[1024];
        for (int i = 0; i < 256; i++) {
            color_palette[i * 4 + 0] = (byte) (i); //bule
            color_palette[i * 4 + 1] = (byte) (i); //green
            color_palette[i * 4 + 2] = (byte) (i); //red
            color_palette[i * 4 + 3] = (byte) 0; //padding
        }
        return color_palette;
    }


    //adds dtata of Source array to Destinition array at the Index
   private   boolean Copy_to_Index(byte[] destination, byte[] source, int index) {
        try {
            for (int i = 0; i < source.length; i++) {
                destination[i + index] = source[i];
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    //create different part of a bitmap file
  private    void create_parts(Bitmap img) {
        //Create Bitmap Data
        Bitmap_Data = ConvertToGrayscale(img);
        //Create Bitmap File Header (populate BMP_File_Header array)
        Copy_to_Index(BMP_File_Header, new byte[]{(byte) 'B', (byte) 'M'}, 0); //magic number
        Copy_to_Index(BMP_File_Header, writeInt(BMP_File_Header.length
                + DIB_header.length + Color_palette.length + Bitmap_Data.length), 2); //file size
        Copy_to_Index(BMP_File_Header, new byte[]{(byte) 'M', (byte) 'C', (byte) 'A', (byte) 'T'}, 6); //reserved for application generating the bitmap file (not imprtant)
        Copy_to_Index(BMP_File_Header, writeInt(BMP_File_Header.length
                + DIB_header.length + Color_palette.length), 10); //bitmap raw data offset
        //Create DIB Header (populate DIB_header array)
        Copy_to_Index(DIB_header, writeInt(DIB_header.length), 0); //DIB header length
        Copy_to_Index(DIB_header, writeInt(((Bitmap) img).getWidth()), 4); //image width
        Copy_to_Index(DIB_header, writeInt(((Bitmap) img).getHeight()), 8); //image height
        Copy_to_Index(DIB_header, new byte[]{(byte) 1, (byte) 0}, 12); //color planes. N.B. Must be set to 1
        Copy_to_Index(DIB_header, new byte[]{(byte) 8, (byte) 0}, 14); //bits per pixel
        Copy_to_Index(DIB_header, writeInt(0), 16); //compression method N.B. BI_RGB = 0
        Copy_to_Index(DIB_header, writeInt(Bitmap_Data.length), 20); //lenght of raw bitmap data
        Copy_to_Index(DIB_header, writeInt(1000), 24); //horizontal reselution N.B. not important
        Copy_to_Index(DIB_header, writeInt(1000), 28); //vertical reselution N.B. not important
        Copy_to_Index(DIB_header, writeInt(256), 32); //number of colors in the palette
        Copy_to_Index(DIB_header, writeInt(0), 36); //number of important colors used N.B. 0 = all colors are imprtant
        //Create Color palett
        Color_palette = create_palette();
    }


    //convert the color pixels of Source image into a grayscale bitmap (raw data)
  private    byte[] ConvertToGrayscale(Bitmap Source) {
        Bitmap source = (Bitmap) Source;
        int padding = (source.getWidth() % 4) != 0 ? 4 - (source.getWidth() % 4) : 0; //determine padding needed for bitmap file
        byte[] bytes = new byte[source.getWidth() * source.getHeight() + padding * source.getHeight()]; //create array to contain bitmap data with paddin
        for (int y = 0; y < source.getHeight(); y++) {
            for (int x = 0; x < source.getWidth(); x++) {
                int pixel = source.getPixel(x, y);
                int g = (int) (0.3 * Color.red(pixel) + 0.59 * Color.green(pixel) + 0.11 * Color.blue(pixel)); //grayscale shade corresponding to rgb
                bytes[(source.getHeight() - 1 - y) * source.getWidth() + (source.getHeight() - 1 - y) * padding + x] = (byte) g;
            }
            //add the padding
            for (int i = 0; i < padding; i++) {
                bytes[(source.getHeight() - y) * source.getWidth() + (source.getHeight() - 1 - y) * padding + i] = (byte) 0;
            }
        }
        return bytes;
    }


    /**
     * Write integer to little-endian
     *
     * @param value
     * @return
     * @throws IOException
     */
    private  byte[] writeInt(int value) {
        byte[] 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;
    }
}
like image 41
naidu Avatar answered Oct 26 '22 23:10

naidu


Note, the code above is very slow. I've found that to optimize the code above it's necessary to make a byte array to store all the data before you put it. Of course, I was working in Xamarin C# so maybe that's why. Anyway, here's my Xamarin code in case anyone has the same problem.

      public class AndroidBmpUtil
        {

            private static int BMP_WIDTH_OF_TIMES = 4;
            private static 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 static byte[] ConvertAndroidBitmapByteArray(Bitmap orgBitmap, String filePath)
            {
                if (orgBitmap == null)
                {
                    return null;
                }

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

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

                //image dummy data size
                //reason : the amount of bytes per image row must be a multiple of 4 (requirements of bmp format)
                byte[] dummyBytesPerRow = null;
                bool hasDummy = false;
                int rowWidthInBytes = BYTE_PER_PIXEL * width; //source image width * number of bytes to encode one pixel.
                if (rowWidthInBytes % BMP_WIDTH_OF_TIMES > 0)
                {
                    hasDummy = true;
                    //the number of dummy bytes we need to add on each row
                    dummyBytesPerRow = new byte[(BMP_WIDTH_OF_TIMES - (rowWidthInBytes % BMP_WIDTH_OF_TIMES))];
                    //just fill an array with the dummy bytes we need to append at the end of each row
                    for (int i = 0; i < dummyBytesPerRow.Length; i++)
                    {
                        dummyBytesPerRow[i] = (byte)0xFF;
                    }
                }

                //an array to receive the pixels from the source image
                int[] pixels = new int[width * height];

                //the number of bytes used in the file to store raw image data (excluding file headers)
                int imageSize = (rowWidthInBytes + (hasDummy ? dummyBytesPerRow.Length : 0)) * height;
                //file headers size
                int imageDataOffset = 0x36;

                //final size of the file
                int fileSize = imageSize + imageDataOffset;

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

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

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

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

                //reserved
                buffer.Put(writeShort((short)0));
                buffer.Put(writeShort((short)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
                //if we add 3 dummy bytes per row : it means we add a pixel (and the image width is modified.
                buffer.Put(writeInt(width + (hasDummy ? (dummyBytesPerRow.Length == 3 ? 1 : 0) : 0)));
                buffer.Put(writeInt(height));

                //planes
                buffer.Put(writeShort((short)1));

                //bit count
                buffer.Put(writeShort((short)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 */
                int row = height;
                int col = width;
                int startPosition = (row - 1) * col;
                int endPosition = row * col;

                // This while loop is a lengthy process
                // Puts take a while so only do one by creating a big array called final
                byte[] final = new byte[0];
                while (row > 0)
                {
                    // This array is also used to cut down on time of puts
                    byte[] b = new byte[(endPosition - startPosition)*3];
                    int counter = 0;
                    for (int i = startPosition; i < endPosition; i++)
                    {

                        b[counter] = (byte)((pixels[i] & 0x000000FF));
                        b[counter + 1] = (byte)((pixels[i] & 0x0000FF00) >> 8);
                        b[counter + 2] = (byte)((pixels[i] & 0x00FF0000) >> 16);
                        counter += 3;
                    }
                    int finalPriorLength = final.Length;
                    Array.Resize<byte>(ref final, finalPriorLength + b.Length);
                    Array.Copy(b, 0, final, finalPriorLength, b.Length);

                    if (hasDummy)
                    {
                        finalPriorLength = final.Length;
                        Array.Resize<byte>(ref final, finalPriorLength + dummyBytesPerRow.Length);
                        Array.Copy(dummyBytesPerRow, 0, final, finalPriorLength, dummyBytesPerRow.Length);
                    }
                    row--;
                    endPosition = startPosition;
                    startPosition = startPosition - col;
                }
                buffer.Put(final);
                buffer.Rewind();

                IntPtr classHandle = JNIEnv.FindClass("java/nio/ByteBuffer");
                IntPtr methodId = JNIEnv.GetMethodID(classHandle, "array", "()[B");
                IntPtr resultHandle = JNIEnv.CallObjectMethod(buffer.Handle, methodId);
                byte[] result = JNIEnv.GetArray<byte>(resultHandle);
                JNIEnv.DeleteLocalRef(resultHandle);

                return result;
            }

            /**
             * Write integer to little-endian
             * @param value
             * @return
             * @throws IOException
             */
            private static byte[] writeInt(int value)
            {
                byte[] 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 short to little-endian byte array
             * @param value
             * @return
             * @throws IOException
             */
            private static byte[] writeShort(short value)
            {
                byte[] b = new byte[2];

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

                return b;
            }
        }
    }

To use it here's the calling code:

using (FileStream outStream = new    FileStream(@yourFilePath, FileMode.Create))
{
    Bitmap Signature = Bitmap.CreateBitmap(user defined values...); 
    byte[] buffer = AndroidBmpUtil.ConvertAndroidBitmapByteArray(Signature, @yourFilePath); 

    // Actually create the file                                 
    outStream.Write(buffer, 0, buffer.Length);
}
like image 44
aktikt1 Avatar answered Oct 27 '22 00:10

aktikt1