text: /*====================================================================*
   -  Copyright (C) 2001 Leptonica.  All rights reserved.
   -
   -  Redistribution and use in source and binary forms, with or without
   -  modification, are permitted provided that the following conditions
   -  are met:
   -  1. Redistributions of source code must retain the above copyright
   -     notice, this list of conditions and the following disclaimer.
   -  2. Redistributions in binary form must reproduce the above
   -     copyright notice, this list of conditions and the following
   -     disclaimer in the documentation and/or other materials
   -     provided with the distribution.
   -
   -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
   -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
   -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *====================================================================*/
  
  /*
   *  leptwin.c
   *
   *    This file contains Leptonica routines needed only on Microsoft Windows
   *
   *    Currently it only contains one public function
   *    (based on dibsectn.c by jmh, 03-30-98):
   *
   *      HBITMAP    pixGetWindowsHBITMAP(PIX *pix)
   */
  
  #ifdef _WIN32
  #include <stdlib.h>
  #include <string.h>
  #include BOSS_OPENALPR_U_allheaders_h //original-code:"allheaders.h"
  #include BOSS_OPENALPR_U_leptwin_h //original-code:"leptwin.h"
  
  /* Macro to determine the number of bytes per line in the DIB bits.
   * This accounts for DWORD alignment by adding 31 bits,
   * then dividing by 32, then rounding up to the next highest
   * count of 4-bytes.  Then, we multiply by 4 to get the total byte count.  */
  #define BYTESPERLINE(Width, BPP) ((l_int32)((((DWORD)(Width) * (DWORD)(BPP) + 31) >> 5)) << 2)
  
  
  /* **********************************************************************
    DWORD DSImageBitsSize(LPBITMAPINFO pbmi)
  
    PARAMETERS:
      LPBITMAPINFO - pointer to a BITMAPINFO describing a DIB
  
    RETURNS:
      DWORD    - the size, in bytes, of the DIB's image bits
  
    REMARKS:
      Calculates and returns the size, in bytes, of the image bits for
      the DIB described by the BITMAPINFO.
  ********************************************************************** */
  static DWORD
  DSImageBitsSize(LPBITMAPINFO pbmi)
  {
      switch(pbmi->bmiHeader.biCompression)
      {
      case BI_RLE8:  /* wrong if haven't called DSCreateDIBSection or
                      * CreateDIBSection with this pbmi */
      case BI_RLE4:
          return pbmi->bmiHeader.biSizeImage;
          break;
      default:  /* should not have to use "default" */
      case BI_RGB:
      case BI_BITFIELDS:
          return BYTESPERLINE(pbmi->bmiHeader.biWidth, \
                     pbmi->bmiHeader.biBitCount * pbmi->bmiHeader.biPlanes) *
                 pbmi->bmiHeader.biHeight;
          break;
      }
      return 0;
  }
  
  /* **********************************************************************
    DWORD ImageBitsSize(HBITMAP hbitmap)
  
    PARAMETERS:
      HBITMAP - hbitmap
  
    RETURNS:
      DWORD    - the size, in bytes, of the HBITMAP's image bits
  
    REMARKS:
      Calculates and returns the size, in bytes, of the image bits for
      the DIB described by the HBITMAP.
  ********************************************************************** */
  static DWORD
  ImageBitsSize(HBITMAP hBitmap)
  {
      DIBSECTION  ds;
  
      GetObject(hBitmap, sizeof(DIBSECTION), &ds);
      switch( ds.dsBmih.biCompression )
      {
      case BI_RLE8:  /* wrong if haven't called DSCreateDIBSection or
                      * CreateDIBSection with this pbmi */
      case BI_RLE4:
          return ds.dsBmih.biSizeImage;
          break;
      default:  /* should not have to use "default" */
      case BI_RGB:
      case BI_BITFIELDS:
          return BYTESPERLINE(ds.dsBmih.biWidth, \
                              ds.dsBmih.biBitCount * ds.dsBmih.biPlanes) *
                              ds.dsBmih.biHeight;
          break;
      }
      return 0;
  }
  
  /*!
   *  setColormap(LPBITMAPINFO pbmi, PIXCMAP *cmap)
   *
   *      Input:  pbmi (pointer to a BITMAPINFO describing a DIB)
   *              cmap (leptonica colormap)
   *      Return: number of colors in cmap
   */
  static int
  setColormap(LPBITMAPINFO  pbmi,
              PIXCMAP      *cmap)
  {
  l_int32  i, nColors, rval, gval, bval;
  
      nColors = pixcmapGetCount(cmap);
      for (i = 0; i < nColors; i++) {
          pixcmapGetColor(cmap, i, &rval, &gval, &bval);
          pbmi->bmiColors[i].rgbRed = rval;
          pbmi->bmiColors[i].rgbGreen = gval;
          pbmi->bmiColors[i].rgbBlue = bval;
          pbmi->bmiColors[i].rgbReserved = 0;
      }
      pbmi->bmiHeader.biClrUsed = nColors;
      return nColors;
  }
  
  /* **********************************************************************
    HBITMAP DSCreateBitmapInfo(l_int32 width, l_int32 height, l_int32 depth,
                               PIXCMAP *cmap)
  
    PARAMETERS:
      l_int32 width - Desired width of the DIBSection
      l_int32 height - Desired height of the DIBSection
      l_int32 depth - Desired bit-depth of the DIBSection
      PIXCMAP cmap - leptonica colormap for depths < 16
  
    RETURNS:
      LPBITMAPINFO - a ptr to BITMAPINFO of the desired size and bit-depth
                     NULL on failure
  
    REMARKS:
      Creates a BITMAPINFO based on the criteria passed in as parameters.
  
  ********************************************************************** */
  static LPBITMAPINFO
  DSCreateBitmapInfo(l_int32 width,
                     l_int32 height,
                     l_int32 depth,
                     PIXCMAP *cmap)
  {
  l_int32       nInfoSize;
  LPBITMAPINFO  pbmi;
  LPDWORD       pMasks;
  
      nInfoSize = sizeof(BITMAPINFOHEADER);
      if( depth <= 8 )
          nInfoSize += sizeof(RGBQUAD) * (1 << depth);
      if((depth == 16) || (depth == 32))
          nInfoSize += (3 * sizeof(DWORD));
  
          /* Create the header big enough to contain color table and
           * bitmasks if needed. */
      pbmi = (LPBITMAPINFO)malloc(nInfoSize);
      if (!pbmi)
          return NULL;
  
      ZeroMemory(pbmi, nInfoSize);
      pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
      pbmi->bmiHeader.biWidth = width;
      pbmi->bmiHeader.biHeight = height;
      pbmi->bmiHeader.biPlanes = 1;
      pbmi->bmiHeader.biBitCount = depth;
  
          /* override below for 16 and 32 bpp */
      pbmi->bmiHeader.biCompression = BI_RGB;
  
          /*  ?? not sure if this is right?  */
      pbmi->bmiHeader.biSizeImage = DSImageBitsSize(pbmi);
  
      pbmi->bmiHeader.biXPelsPerMeter = 0;
      pbmi->bmiHeader.biYPelsPerMeter = 0;
      pbmi->bmiHeader.biClrUsed = 0;  /* override below */
      pbmi->bmiHeader.biClrImportant = 0;
  
      switch(depth)
      {
          case 24:
                  /* 24bpp requires no special handling */
              break;
          case 16:
                  /* if it's 16bpp, fill in the masks and override the
                   * compression.  These are the default masks -- you
                   * could change them if needed. */
              pMasks = (LPDWORD)(pbmi->bmiColors);
              pMasks[0] = 0x00007c00;
              pMasks[1] = 0x000003e0;
              pMasks[2] = 0x0000001f;
              pbmi->bmiHeader.biCompression = BI_BITFIELDS;
              break;
          case 32:
                  /* if it's 32 bpp, fill in the masks and override
                   * the compression */
              pMasks = (LPDWORD)(pbmi->bmiColors);
              /*pMasks[0] = 0x00ff0000; */
              /*pMasks[1] = 0x0000ff00; */
              /*pMasks[2] = 0x000000ff; */
              pMasks[0] = 0xff000000;
              pMasks[1] = 0x00ff0000;
              pMasks[2] = 0x0000ff00;
  
              pbmi->bmiHeader.biCompression = BI_BITFIELDS;
              break;
          case 8:
          case 4:
          case 1:
              setColormap(pbmi, cmap);
              break;
      }
      return pbmi;
  }
  
  /* **********************************************************************
    HBITMAP DSCreateDIBSection(l_int32 width, l_int32 height, l_int32 depth,
                               PIXCMAP *cmap)
  
    PARAMETERS:
      l_int32 width - Desired width of the DIBSection
      l_int32 height - Desired height of the DIBSection
      l_int32 depth - Desired bit-depth of the DIBSection
      PIXCMAP cmap - leptonica colormap for depths < 16
  
    RETURNS:
      HBITMAP      - a DIBSection HBITMAP of the desired size and bit-depth
                     NULL on failure
  
    REMARKS:
      Creates a DIBSection based on the criteria passed in as parameters.
  
  ********************************************************************** */
  static HBITMAP
  DSCreateDIBSection(l_int32  width,
                     l_int32  height,
                     l_int32  depth,
                     PIXCMAP  *cmap)
  {
  HBITMAP       hBitmap;
  l_int32       nInfoSize;
  LPBITMAPINFO  pbmi;
  HDC           hRefDC;
  LPBYTE        pBits;
  
      pbmi = DSCreateBitmapInfo (width, height, depth, cmap);
      if (!pbmi)
          return NULL;
  
      hRefDC = GetDC(NULL);
      hBitmap = CreateDIBSection(hRefDC, pbmi, DIB_RGB_COLORS,
                                 (void **) &pBits, NULL, 0);
      nInfoSize = GetLastError();
      ReleaseDC(NULL, hRefDC);
      free(pbmi);
  
      return hBitmap;
  }
  
  
  /*!
   *  pixGetWindowsHBITMAP()
   *
   *      Input:  pix
   *      Return: Windows hBitmap, or null on error
   *
   *  Notes:
   *      (1) It's the responsibility of the caller to destroy the
   *          returned hBitmap with a call to DeleteObject (or with
   *          something that eventually calls DeleteObject).
   */
  HBITMAP
  pixGetWindowsHBITMAP(PIX  *pix)
  {
  l_int32    width, height, depth;
  l_uint32  *data;
  HBITMAP    hBitmap = NULL;
  BITMAP     bm;
  DWORD      imageBitsSize;
  PIX       *pixt = NULL;
  PIXCMAP   *cmap;
  
      PROCNAME("pixGetWindowsHBITMAP");
      if (!pix)
          return (HBITMAP)ERROR_PTR("pix not defined", procName, NULL);
  
      pixGetDimensions(pix, &width, &height, &depth);
      cmap = pixGetColormap(pix);
  
      if (depth == 24) depth = 32;
      if (depth == 2) {
          pixt = pixConvert2To8(pix, 0, 85, 170, 255, TRUE);
          if (!pixt)
              return (HBITMAP)ERROR_PTR("unable to convert pix from 2bpp to 8bpp",
                      procName, NULL);
          depth = pixGetDepth(pixt);
          cmap = pixGetColormap(pixt);
      }
  
      if (depth < 16) {
          if (!cmap)
              cmap = pixcmapCreateLinear(depth, 1<<depth);
      }
  
      hBitmap = DSCreateDIBSection(width, height, depth, cmap);
      if (!hBitmap)
          return (HBITMAP)ERROR_PTR("Unable to create HBITMAP", procName, NULL);
  
          /* By default, Windows assumes bottom up images */
      if (pixt)
          pixt = pixFlipTB(pixt, pixt);
      else
          pixt = pixFlipTB(NULL, pix);
  
          /* "standard" color table assumes bit off=black */
      if (depth == 1) {
          pixInvert(pixt, pixt);
      }
  
          /* Don't byte swap until done manipulating pix! */
      if (depth <= 16)
          pixEndianByteSwap(pixt);
  
      GetObject (hBitmap, sizeof(BITMAP), &bm);
      imageBitsSize = ImageBitsSize(hBitmap);
      data = pixGetData(pixt);
      if (data) {
          memcpy (bm.bmBits, data, imageBitsSize);
      } else {
          DeleteObject (hBitmap);
          hBitmap = NULL;
      }
      pixDestroy(&pixt);
  
      return hBitmap;
  }
  
  #endif   /* _WIN32 */
  