0

I am trying to get a Bitmap image from a fingerprint device SDK. The SDK provided a struct for preview image, I failed to convert it to Bitmap:

public struct IBSU_ImageData
{
    /* Pointer to image buffer.  If this structure is supplied by a callback function, this pointer 
     * must not be retained; the data should be copied to an application buffer for any processing
     * after the callback returns. */
    public IntPtr Buffer;

    /* Image horizontal size (in pixels). */
    public uint Width;

    /* Image vertical size (in pixels). */
    public uint Height;

    /* Horizontal image resolution (in pixels/inch). */
    public double ResolutionX;

    /* Vertical image resolution (in pixels/inch). */
    public double ResolutionY;

    /* Image acquisition time, excluding processing time (in seconds). */
    public double FrameTime;

    /* Image line pitch (in bytes).  A positive value indicates top-down line order; a negative 
     * value indicates bottom-up line order. */
    public int Pitch;

    /* Number of bits per pixel. */
    public byte BitsPerPixel;

    /* Image color format. */
    public IBSU_ImageFormat Format;

    /* Marks image as the final processed result from the capture.  If this is FALSE, the image is
     * a preview image or a preliminary result. */
    public bool IsFinal;

    /* Threshold of image processing. */
    public uint ProcessThres;
}

public enum IBSU_ImageFormat
{
    IBSU_IMG_FORMAT_GRAY,                                    /* Gray scale image. */
    IBSU_IMG_FORMAT_RGB24,                                   /* 24 bit RGB color image. */
    IBSU_IMG_FORMAT_RGB32,                                   /* True color RGB image. */
    IBSU_IMG_FORMAT_UNKNOWN                                  /* Unknown format. */
}

I've tried use Image.FromHbitmap(imageData) but not work.

I debug and give the IBSU_ImageData content:

Buffer : 0x1741d020
Width : 1600
Height : 1500
ResolutionX : 500
ResolutionY : 500
FrameTime : 0.100421
Pitch : -1600
BitsPerPixel : 8
Format : IBSU_IMG_FORMAT_GRAY
IsFinal : false
ProcessThres : 2
Oh My Dog
  • 781
  • 13
  • 32
  • 1
    It doesn't work is not a programming or compiler outcome – TheGeneral Feb 14 '18 at 02:25
  • 1
    Also what is this `imageData` you speak of, its not referenced anywhere in the code or information you supplied – TheGeneral Feb 14 '18 at 02:27
  • 1
    Also `FromHbitmap` converts form GDI bitmap handle, of type` HBITMAP` does the documentation say this is what is returned – TheGeneral Feb 14 '18 at 02:29
  • 1
    Also the Title Description is innately broad. Who knows what that intPtr points to, it could be a Goldfish for all we know – TheGeneral Feb 14 '18 at 02:31
  • FromHBitmap didn’t work because the fingerprint image pointer probably lacks the bitmap header. Try the [Bitmap constructor](https://msdn.microsoft.com/de-de/library/zy1a2d14(v=vs.110).aspx) where PixelFormat would need to be derived from IBSU_ImageFormat and the stride could be the (positive) Pitch or can be calculated as Width*BitsPerPixel/8+additional padding – ckuri Feb 14 '18 at 02:39

2 Answers2

0

You have all the data you need. Simply construct the image from that data. I wrote a function before that can build a Bitmap from a byte array and the relevant information.

You can copy the buffer contents from the Buffer pointer using Marshal.Copy, into an array of pitch * height bytes. You just need to be careful with the negative pitch, though; it indicates BMP-style bottom-to-top lines.

public static Bitmap GetBitmapFromIBSU(IBSU_ImageData imageData)
{
    // Can't handle this.
    if (imageData.Format == IBSU_ImageFormat.IBSU_IMG_FORMAT_UNKNOWN)
        throw new NotSupportedException();
    Byte[] data = new byte[imageData.Width * Math.Abs(imageData.Pitch)];
    Marshal.Copy(imageData.Buffer, data, 0, data.Length);
    // Write this function yourself. They're both enums so a simple switch-case should do.
    // GRAY probably needs to be seen as indexed 8bpp; then you need to give a generated
    // 256-entry black-to-white colour fade palette to BuildImage in the next step.
    PixelFormat format = ConvertPixelformat(imageData.Format);
    // The function I linked in the description.
    Bitmap image = BuildImage(data, imageData.Width, imageData.Height, imageData.Pitch, format, null, null);
    bitmap.SetResolution(imageData.ResolutionX, imageData.ResolutionY);
    return bitmap;
}
Nyerguds
  • 5,360
  • 1
  • 31
  • 63
  • Hi everybody, I'm facing the same issue, but still not able to figure out how to deal with this Buffer, tried the marshal copy , built the image using different pixelformat, still facing the GDI+ error, any news>? – Mouad Cherkaoui Sep 26 '22 at 10:08
  • @MouadCherkaoui Could you debug through and get the width, height, stride (called 'pitch' here for some reason), data length and image format for your specific case that comes out of that data? With that it's easy to see what's wrong. – Nyerguds Sep 29 '22 at 14:36
  • I finally find out what was wrong, it was just that the pixels array and pixel format is for a gray scaled images, but the real pixel format is 8BppIndexed, thus when trying to build the image using the wrong pixel format 16BppGrayScale it causes errors! – Mouad Cherkaoui Oct 05 '22 at 10:30
  • 1
    `16BppGrayScale` is not supported in `System.Drawing` anyway. It exists in the list of formats, but it is not implemented. – Nyerguds Oct 05 '22 at 11:14
0
        public static Bitmap toBitmap(this IBSU_ImageData imageData)
    {
        int w = (int)imageData.Width;
        int h = (int)imageData.Height;

        byte[] pixels = new byte[w * h];

        Marshal.Copy(imageData.Buffer, pixels, 0, pixels.Length);

        var bitmap = new Bitmap(w, h, PixelFormat.Format8bppIndexed);

        //bitmap.SetResolution((float)imageData.ResolutionY,
        //                     (float)imageData.ResolutionX);

        ///////////////////////////////////////
        // Set grayscale palette
        ///////////////////////////////////////
        ColorPalette colorPalette = bitmap.Palette;
        for (int i = 0; i < colorPalette.Entries.Length; i++)
        {
            colorPalette.Entries[i] = Color.FromArgb(i, i, i);
        }

        bitmap.Palette = colorPalette;

        var _imageData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

        Marshal.Copy(pixels, 0, _imageData.Scan0, pixels.Length);

        bitmap.UnlockBits(_imageData);
        return bitmap;
    }