title: Windows Biometric Framework Extract image from fingerprint sensor
body: <p>I'm trying to extract fingerprint images from my fingerprint sensors.</p>
  
  <p>With my first fingerprint sensor (113x115) it works great. </p>
  
  <p>The current sensor (114x57) it gives me a noisy image.</p>
  
  <p>The code has been adapted to the sensor data (size, padding, width, height).</p>
  
  <p>ImgCompressionAlg = 0; </p>
  
  <p>PixelDepth = 8</p>
  
  <pre><code>#include "stdafx.h"
  #include "Strsafe.h"
  
  using namespace std;
  
  //-----------------------------------------------------------------------------
  // Forward declarations of local functions for Private Pool Setup.
  
  HRESULT CaptureSample();
  bool SaveBMP(BYTE* buffer, int width, int height, int pixelPerVertical, int pixelPerHorizontal, long paddedsize, LPCTSTR bmpfile, BYTE* firstPixel);
  
  //-----------------------------------------------------------------------------
  
  int _tmain(int argc, _TCHAR* argv[])
  {
      HRESULT hr = S_OK;
      hr = CaptureSample();
      _tprintf(_T("Capture Sample: hr = 0x%x\n"), hr);
  
      std::cin;
  
      return 0;
  }
  
  //-----------------------------------------------------------------------------
  
  HRESULT CaptureSample()
  {
  restart:
      HRESULT hr = S_OK;
      WINBIO_SESSION_HANDLE sessionHandle = NULL;
      WINBIO_UNIT_ID unitId = 0;
      WINBIO_REJECT_DETAIL rejectDetail = 0;
      PWINBIO_BIR sample = NULL;
      SIZE_T sampleSize = 0;
      PWINBIO_UNIT_SCHEMA unitSchema = NULL;
      SIZE_T unitCount = 0;
      SIZE_T index = 0;
      ofstream ofs;
      string name;
  
      // Connect to the system pool.  
      hr = WinBioOpenSession(
          WINBIO_TYPE_FINGERPRINT,    // Service provider
          WINBIO_POOL_SYSTEM,         // Pool type
          WINBIO_FLAG_RAW,            // Access: Capture raw data
          NULL,                       // Array of biometric unit IDs
          0,                          // Count of biometric unit IDs
          WINBIO_DB_DEFAULT,          // Default database
          &amp;sessionHandle              // [out] Session handle
      );
      if (FAILED(hr))
      {
          wprintf_s(L"\n WinBioOpenSession failed. hr = 0x%x\n", hr);
          goto e_Exit;
      }
      // Enumerate the installed biometric units.
      hr = WinBioEnumBiometricUnits(
          WINBIO_TYPE_FINGERPRINT,        // Type of biometric unit
          &amp;unitSchema,                    // Array of unit schemas
          &amp;unitCount);                   // Count of unit schemas
  
      if (FAILED(hr))
      {
          wprintf_s(L"\n WinBioEnumBiometricUnits failed. hr = 0x%x\n", hr);
          goto e_Exit;
      }
  
      // Display information for each installed biometric unit.
      wprintf_s(L"\nSensors: \n");
      for (index = 0; index &lt; unitCount; ++index)
      {
          wprintf_s(L"\n[%d]: \tUnit ID: %d\n",
              index,
              unitSchema[index].UnitId);
          wprintf_s(L"\tDevice instance ID: %s\n",
              unitSchema[index].DeviceInstanceId);
          wprintf_s(L"\tPool type: %d\n",
              unitSchema[index].PoolType);
          wprintf_s(L"\tBiometric factor: %d\n",
              unitSchema[index].BiometricFactor);
          wprintf_s(L"\tSensor subtype: %d\n",
              unitSchema[index].SensorSubType);
          wprintf_s(L"\tSensor capabilities: 0x%08x\n",
              unitSchema[index].Capabilities);
          wprintf_s(L"\tDescription: %s\n",
              unitSchema[index].Description);
          wprintf_s(L"\tManufacturer: %s\n",
              unitSchema[index].Manufacturer);
          wprintf_s(L"\tModel: %s\n",
              unitSchema[index].Model);
          wprintf_s(L"\tSerial no: %s\n",
              unitSchema[index].SerialNumber);
          wprintf_s(L"\tFirmware version: [%d.%d]\n",
              unitSchema[index].FirmwareVersion.MajorVersion,
              unitSchema[index].FirmwareVersion.MinorVersion);
      }
  
      wprintf_s(L"\n Pick a Sensor: ");
      int i;
      std::cin &gt;&gt; i;
  
      unitId = unitSchema[i].UnitId;
  
      // Capture a biometric sample.
      wprintf_s(L"\n Calling WinBioCaptureSample - Swipe sensor...\n");
      hr = WinBioCaptureSample(
          sessionHandle,
          WINBIO_NO_PURPOSE_AVAILABLE,
          WINBIO_DATA_FLAG_RAW,
          &amp;unitId,
          &amp;sample,
          &amp;sampleSize,
          &amp;rejectDetail
      );
      if (FAILED(hr))
      {
          if (hr == WINBIO_E_BAD_CAPTURE)
          {
              wprintf_s(L"\n Bad capture; reason: %d\n", rejectDetail);
          }
          else
          {
              wprintf_s(L"\n WinBioCaptureSample failed. hr = 0x%x\n", hr);
          }
          goto e_Exit;
      }
  
      wprintf_s(L"\n Swipe processed - Unit ID: %d\n", unitId);
      wprintf_s(L"\n Captured %d bytes.\n", sampleSize);
  
      PWINBIO_BIR_HEADER BirHeader = (PWINBIO_BIR_HEADER) (((PBYTE)sample) + sample-&gt;HeaderBlock.Offset); //header points to the offset of the header block
      PWINBIO_BDB_ANSI_381_HEADER AnsiBdbHeader = (PWINBIO_BDB_ANSI_381_HEADER)(((PBYTE)sample) + sample-&gt;StandardDataBlock.Offset); //header points to the beginning of the standard data block
      PWINBIO_BDB_ANSI_381_RECORD AnsiBdbRecord = (PWINBIO_BDB_ANSI_381_RECORD)(((PBYTE)AnsiBdbHeader) + sizeof(WINBIO_BDB_ANSI_381_HEADER)); //record points to the record of the standard data block
  
      BYTE* firstPixel = (BYTE*)((BYTE*)AnsiBdbRecord) + sizeof(WINBIO_BDB_ANSI_381_RECORD); //points to the data of first pixel
  
      wprintf_s(L"\n ID: %d\n", AnsiBdbHeader-&gt;ProductId.Owner);
      wprintf_s(L" Horizontal Img. Res.: %d\n", AnsiBdbHeader-&gt;HorizontalImageResolution);
      wprintf_s(L" Horizontal Scan Img. Res.: %d pixels/centimeter\n", AnsiBdbHeader-&gt;HorizontalScanResolution);
      wprintf_s(L" Vertical Img. Res.: %d\n", AnsiBdbHeader-&gt;VerticalImageResolution);
      wprintf_s(L" Vertical Scan Img. Res.: %d pixels/centimeter\n", AnsiBdbHeader-&gt;VerticalScanResolution);
      wprintf_s(L" Pixel Depth: %d\n", AnsiBdbHeader-&gt;PixelDepth); //number of bits in one pixel
      wprintf_s(L" Element Count: %d\n", AnsiBdbHeader-&gt;ElementCount); //number of images
  
      wprintf_s(L" Width: %d\n", AnsiBdbRecord-&gt;HorizontalLineLength);
      wprintf_s(L" Height: %d\n", AnsiBdbRecord-&gt;VerticalLineLength);
      wprintf_s(L" Blocklength: %d\n", AnsiBdbRecord-&gt;BlockLength);
      wprintf_s(L" Compression Algorithm: %d\n", AnsiBdbHeader-&gt;ImageCompressionAlg);
  
      wprintf_s(L" Address of First Pixel in HEX: 0x%x\n", firstPixel);
      wprintf_s(L" Address of First Pixel in DEC: %d\n", firstPixel);
  
      //AnsiBdbRecord-&gt;BlockLength is size of data + record header
      long blocklength = AnsiBdbRecord-&gt;BlockLength - sizeof(AnsiBdbRecord); //blocklength is size of raw image data
      //long size = sizeof(char) * 4;
  
      bool b = SaveBMP(firstPixel, AnsiBdbRecord-&gt;HorizontalLineLength, AnsiBdbRecord-&gt;VerticalLineLength, AnsiBdbRecord-&gt;VerticalLineLength, AnsiBdbRecord-&gt;HorizontalLineLength, blocklength, L"C:\\Users\ChickenDuy\Documents\bio_key_extraction\bio_key_extraction\bio_key_extraction\fingerprint.bmp", firstPixel);
  
      if (b) {
          wprintf_s(L"\n SaveBMP succeeded");
      }
      else {
          wprintf_s(L"\n SaveBMP failed");
      }
  
  
  e_Exit:
      if (sample != NULL)
      {
          WinBioFree(sample);
          sample = NULL;
      }
      if (unitSchema != NULL)
      {
          WinBioFree(unitSchema);
          unitSchema = NULL;
      }
      if (sessionHandle != NULL)
      {
          WinBioCloseSession(sessionHandle);
          sessionHandle = NULL;
      }
  
      wprintf_s(L"\n Press 0 to repeat.\n Press 1 to exit\n. ");
      std::cin &gt;&gt; i;
  
      if (i == 0) {
          goto restart;
      }
  
      return hr;
  }
  
  bool SaveBMP(BYTE* buffer, int width, int height, int pixelPerVertical, int pixelPerHorizontal, long data_size, LPCTSTR bmpfile, BYTE* firstPixel) {
      BITMAPFILEHEADER bmfh;
      BITMAPINFOHEADER info;
      memset(&amp;bmfh, 0, sizeof(BITMAPFILEHEADER));
      memset(&amp;info, 0, sizeof(BITMAPINFOHEADER));
  
      //long sizeOfColorTable = 4*255*sizeof(char); //size of the color table is 00-FF with a four byte coding RGB0
      int padding = 4 - (width % 4); //calculate the padding needed
  
      bmfh.bfType = 19778; // Don't question it. Magic Word (B and M). It's necessary. Seriously.
      bmfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + data_size; //size of the whole bitmap
      bmfh.bfReserved1 = 0;
      bmfh.bfReserved2 = 0;
      bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //start position of data after the header
  
      info.biSize = sizeof(BITMAPINFOHEADER); //size of the bitmap info header
      info.biWidth = width; //width of the bitmap
      info.biHeight = height; //height of the bitmap
      info.biPlanes = 1; //dimensions of the image
      info.biBitCount = 8; //encoding of raw data -&gt; 8 bits per pixel
      info.biCompression = 0; //compression algorithm
      info.biSizeImage = (width*sizeof(char) + padding*sizeof(char))*height; //size of image data in bytes including padding
      info.biXPelsPerMeter = pixelPerHorizontal;
      info.biYPelsPerMeter = pixelPerVertical;
      info.biClrUsed = 0;
      info.biClrImportant = 0;
  
  
      ofstream bmp("fingerprint.bmp", ios::binary | ios::trunc | ios::out); //open as output and binary file and delete everything in the current .bmp file
  
      if (bmp.is_open()) {
          wprintf_s(L"\n Opening BMP successful\n");
          bmp.write((char*)&amp;bmfh, sizeof(BITMAPFILEHEADER)); //write BitmapFileHeader
          bmp.write((char*)&amp;info, sizeof(BITMAPINFOHEADER)); //write BitmapInfoHeader
      }
      else {
          wprintf_s(L"\n Opening BMP failed\n");
          return false;
      }
  
      //char pixelArray[pWidth][pHeight]; //create a pixel array with the size of the image
      char pixelArray[1];
      BYTE* pixel = new BYTE;
      pixel = &amp;(*firstPixel); //new pointer to the first pixel
  
      int* x = 0;
      ////grey index color array
      for (int i = 0; i &lt; 256; i++) {
              bmp.write((char*) &amp;i, sizeof(char)); //write red
              bmp.write((char*) &amp;i, sizeof(char)); //write green
              bmp.write((char*) &amp;i, sizeof(char)); //write blue
              bmp.write((char*) &amp;x, sizeof(char)); //write 0
              //wprintf(L"\n Saving Color: %x %x %x %x", i, i, i, 0);
      }
  
  
      for (int i = 0; i &lt; height; i++) {
          for (int j = 0; j &lt; width; j++) {
              memset(&amp;pixelArray[0], *pixel, sizeof(char)); //get data from sample and save into array 
              bmp.write((char*)&amp;pixelArray[0], sizeof(char)); //save pixel to bitmap
              pixel = &amp;(*pixel) + sizeof(char); //set pointer to the next byte
              //wprintf(L"\n Saving PixelArray[%d][%d] 0x%x", j, i, *pixel);
          }
          //113 pixels * 3 bytes = 339 bytes -&gt; missing 1 byte (bio_key) because 24bit/3byte pixel depth
          //114 pixels * 1 byte = 114 bytes -&gt; missing 2 bytes (small sensor) because 8bit/1byte pixel depth
          for (int j = 0; j &lt; padding; j++) {
              bmp.write((char*)&amp;x, sizeof(char)); //pad to a multiple of 4 bytes
              //wprintf(L"\n Saving PixelArray[%d][%d] 0x%x", 115, i, 0);
          }
      }       
  bmp.close();
  return true;
  }
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/6UxZZ.png" rel="nofollow noreferrer">Sensor 1</a></p>
  
  <p><a href="https://i.stack.imgur.com/fwxL4.png" rel="nofollow noreferrer">Sensor 2</a></p>
  
  <p>Hope somebody will be able to help.</p>